Simple CRUD REST API with Java EE

by Hayri Cicek


Posted on 02-Aug-2018

In this tutorial we will learn how to create a simple CRUD REST API with Java EE using H2 database and TomEE application server.
H2 is an open source relational database management system written in Java. It can be embedded in Java applications or run in the client-server mode and it is easy to install and deploy.

Tools You Will Need
Maven 3.3+
Your favorite IDE. I'm using NetBeans
JDK 1.8+

Create the Directory Structure
The first thing is to create a directory where we will have our project source files.
Open your terminal and create the directories and the files

$ mkdir simple-javaee-crud-rest-api
$ mkdir -p src/main/java/com/kodnito/restapi/models
$ mkdir -p src/main/java/com/kodnito/restapi/dao
$ mkdir -p src/main/java/com/kodnito/restapi/resources
$ mkdir -p src/main/resources/META-INF
$ mkdir -p src/main/webapp/WEB-INF
$ touch src/main/webapp/WEB-INF/resources.xml
$ touch src/main/resources/META-INF/persistence.xml
$ touch src/main/java/com/kodnito/restapi/models/Todo.java
$ touch src/main/java/com/kodnito/restapi/dao/TodoDAO.java
$ touch src/main/java/com/kodnito/restapi/resources/ApplicationConfig.java
$ touch src/main/java/com/kodnito/restapi/resources/TodoResource.java
$ touch pom.xml

Your directory structure should look like this
$ tree
.
├── pom.xml
└── src
    └── main
        ├── java
        │   └── com
        │       └── kodnito
        │           └── restapi
        │               ├── dao
        │               │   └── TodoDAO.java
        │               ├── models
        │               │   └── Todo.java
        │               └── resources
        │                   ├── ApplicationConfig.java
        │                   └── TodoResource.java
        ├── resources
        │   └── META-INF
        │       └── persistence.xml
        └── webapp
            └── WEB-INF
                └── resources.xml

Now it's time to add some dependencies we need to create the application.
Open the project in your favorite IDE and add the following to the pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.kodnito</groupId>
    <artifactId>simple-javaee-crud-rest-api</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>simple-javaee-crud-rest-api</name>
    <packaging>war</packaging>
    
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <failOnMissingWebXml>false</failOnMissingWebXml>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
   <dependency>
         <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.196</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>eclipselink</artifactId>
            <version>2.7.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomee.maven</groupId>
                <artifactId>tomee-maven-plugin</artifactId>
                <version>7.0.5</version>
                <configuration>
                    <context>restapi</context>
                    <tomeeClassifier>plus</tomeeClassifier>
                    <tomeeHttpPort>8080</tomeeHttpPort>
                    <tomeeShutdownPort>8005</tomeeShutdownPort>
                    <useBinaries>true</useBinaries>
                </configuration>
            </plugin>
        </plugins>

    </build>

</project>

We added Java EE 7 api, H2 database and EclipseLink dependencies and TomEE maven runtime to our application.
In project directory run the following command to download the dependencies.

$ mvn install
TomEE Config
Open src/main/webapp/WEB-INF/resources.xml and add the following to configure DataSource.


<?xml version="1.0" encoding="UTF-8"?>
<tomee>
    <Resource id="jdbc/my_h2_db" type="javax.sql.DataSource">
        JdbcDriver = org.h2.Driver
        JdbcUrl = jdbc:h2:file:~/my_h2_db
        UserName = sa
        Password = sa
        jtaManaged = true
    </Resource>
</tomee>

Now open persistence.xml and add the following to it.


<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
             xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="restapi_PU" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/my_h2_db</jta-data-source>
    <properties>
      <property name="eclipselink.ddl-generation" value="create-tables"/>
      <property name="eclipselink.ddl-generation.output-mode" value="database"/>
    </properties>
  </persistence-unit>
</persistence>


persistence.xml is the standard configuration file for JPA and it has to be included in the META-INF directory
The persistence.xml file defines what provider to be used, the name of the persistence unit, how classes should be mapped to database tables.
eclipselink.ddl-generation will create the database and tables

Entity
Open Todo.java file and add the following

Todo.java

package com.kodnito.restapi.models;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table(name = "todos")
@NamedQueries({
    @NamedQuery(name = "Todo.findAll", query = "SELECT t FROM Todo t")
})
public class Todo implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String task;
    private String description;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTask() {
        return task;
    }

    public void setTask(String task) {
        this.task = task;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public String toString() {
        return "Todo{" + "id=" + id + ", task=" + task + ", description=" + description + '}';
    }

}


@Entity annotation indicates that it is a JPA entity
@Table annotation is used to name the table in the database
@NamedQueries annotation is used to add multiple queries
@NamedQuery annotation defines query with a name
@Id annotation is used to define the primary key and the Id property is also annotated with @GeneratedValue to indicate that the Id should be generated automatically.

Business Logic
Open TodoDAO.java file and add the following

TodoDAO.java

package com.kodnito.restapi.dao;

import com.kodnito.restapi.models.Todo;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class TodoDAO {

    @PersistenceContext(unitName = "restapi_PU")
    EntityManager em;

    public List getAll() {
        return em.createNamedQuery("Todo.findAll", Todo.class).getResultList();
    }

    public Todo findById(Long id) {
        return em.find(Todo.class, id);
    }

    public void update(Todo todo) {
        em.merge(todo);
    }

    public void create(Todo todo) {
        em.persist(todo);
    }

    public void delete(Todo todo) {
        if (!em.contains(todo)) {
            todo = em.merge(todo);
        }

        em.remove(todo);
    }
}


@PersistenceContext annotation injects the EntityManager to be used at runtime.
getAll() method retrieves all the todos from the database and return the entire list.
findById() method finds one Todo Object from the database with ID and returns it
update() method will update existing Todo Object in the database.
create() method will create Todo Object in the database
delete() method will find the Todo Object in the database and delete it.

Resource
Next step is to create the resource class.
Open ApplicationConfig.java and add the following.

ApplicationConfig.java

package com.kodnito.resources;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/api")
public class ApplicationConfig extends Application {

}

@ApplicationPath annotation identifies the application path that will serve as the base for all our endpoints.
Now open TodoResource.java and add the following to it

TodoResource.java

package com.kodnito.restapi.resources;

import com.kodnito.restapi.dao.TodoDAO;
import com.kodnito.restapi.models.Todo;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@RequestScoped
@Path("todos")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class TodoResource {

    @Inject
    TodoDAO todoDAO;

    @GET
    public Response getAll() {
        return Response.ok(todoDAO.getAll()).build();
    }

    @GET
    @Path("{id}")
    public Response getTodo(@PathParam("id") Long id) {
        Todo todo = todoDAO.findById(id);

        return Response.ok(todo).build();
    }

    @PUT
    @Path("{id}")
    public Response update(@PathParam("id") Long id, Todo todo) {
        Todo updateTodo = todoDAO.findById(id);

        updateTodo.setTask(todo.getTask());
        updateTodo.setDescription(todo.getDescription());
        todoDAO.update(updateTodo);

        return Response.ok().build();
    }

    @POST
    public Response create(Todo todo) {
        todoDAO.create(todo);
        return Response.ok().build();
    }

    @DELETE
    @Path("{id}")
    public Response delete(@PathParam("id") Long id) {
        Todo getTodo = todoDAO.findById(id);
        
        todoDAO.delete(getTodo);

        return Response.ok().build();
    }

}

@RequestScoped annotation indicates that this class will be created once every request.
@Path annotation identifies the URI path to which the resource responds.
@Produces annotation will automatically convert the response to JSON format
@Consumes annotation will automatically convert the posted json string here into Todo object
We inject the TodoDAO with the @Inject annotation
@GET annotation maps /todos HTTP GET request to getAll() method, which will retrieve all the todos from the database and return the entire list.
Parameters are accessed with the @PathParam annotation.
@PUT annotation is for handling HTTP PUT request and it is meant to update an existing resource.
@POST annotation is for handling HTTP POST request and it is meant to create a new resource.
@DELETE annotation is for handling HTTP DELETE request.

It's time to test our new rest api.
Download Postman if you don't already have it.
Open your terminal and go the directory where you have your project and type the following command to compile the project and start the TomEE server.

$ mvn package tomee:run

Create TODO

Get TODOS

Update TODO



Delete TODO


Share this: