I remember these days when building something similar in Java required much more body movements, and maybe this was the reason to why some start-ups have chosen other weak typing languages with all their fancy Web frameworks for rapid bootstrapping. This isn't the case anymore, see how easy is creating a REST service that supports all CRUD operations in Java:
1. Define your task model:
/**
* Task model
*/
@Entity
public class Task {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String text;
private Date created = new Date();
private Date completed;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getCompleted() {
return completed;
}
public void setCompleted(Date completed) {
this.completed = completed;
}
}
2. Tell what operations on tasks you're going to support:
/**
* This class defines DB operations on Task entity
*/
public interface TaskRepository extends PagingAndSortingRepository<Task> {
// Magic method name automatically generates needed query
public List<Task> findByCompletedIsNull();
}
3. Configure your application:
/**
* This class is responsible for:
* - Setting up DB connection and ORM
* - Initializing REST service for all found entities
* - Starting Spring application (main entry point)
*/
@ComponentScan
@Configuration
@EnableAutoConfiguration
@EnableJpaRepositories
@EnableTransactionManagement
public class Application extends RepositoryRestMvcConfiguration {
@Bean
public DataSource dataSource() throws PropertyVetoException {
MySQLDataSource dataSource = new MySQLDataSource();
dataSource.setDatabaseName("taskdb");
dataSource.setUserName("user");
dataSource.setPassword("pass");
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
// Database tables will be created/updated automatically due to this:
jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setDatabase(Database.MYSQL);
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter);
entityManagerFactoryBean.setPackagesToScan(getClass().getPackage().getName());
return entityManagerFactoryBean;
}
@Bean
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager();
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
That's all! After invoking this application, you'll get a task complete REST service for free. Let's test it:
Create a new task:
~$ curl -X POST -H "Content-Type: application/json" -d '{"text":"Implement simplest REST Java application"}' http://localhost:8080/tasks
See the task contents:
~$ curl http://localhost:8080/tasks/1
{
"text" : "Implement simplest REST Java application",
"created" : 1395665199000,
"completed" : null,
"_links" : {
"self" : {
"href" : "http://localhost:8080/tasks/1"
}
}
}
Create another task:
~$ curl -X POST -H "Content-Type: application/json" -d '{"text":"Go home"}' http://localhost:8080/tasks
Find all tasks:
~$ curl http://localhost:8080/tasks
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/tasks{?page,size,sort}",
"templated" : true
},
"search" : {
"href" : "http://localhost:8080/tasks/search"
}
},
"_embedded" : {
"tasks" : [ {
"text" : "Implement simplest REST Java application",
"created" : 1395665199000,
"completed" : null,
"_links" : {
"self" : {
"href" : "http://localhost:8080/tasks/1"
}
}
}, {
"text" : "Go home",
"created" : 1395665359000,
"completed" : null,
"_links" : {
"self" : {
"href" : "http://localhost:8080/tasks/2"
}
}
} ]
},
"page" : {
"size" : 20,
"totalElements" : 2,
"totalPages" : 1,
"number" : 0
}
}
(pay an attention to how easy is it implementing pagination using this REST service!)
Mark the first task as complete:
~$ curl -X PATCH -H "Content-Type: application/json" -d "{\"completed\":$(($(date +%s)*1000))}" http://localhost:8080/tasks/1
Find incomplete tasks:
~$ curl http://localhost:8080/tasks/search/findByCompletedIsNull
{
"_embedded" : {
"tasks" : [ {
"text" : "Go home",
"created" : 1395665359000,
"completed" : null,
"_links" : {
"self" : {
"href" : "http://localhost:8080/tasks/2"
}
}
} ]
}
}
Pretty easy and yet powerful, huh?
For more information and instructions for how to compile and run this application, see source code on GitHub.