In this article, we are going to learn how to create a REST API using Java EE 8, MicroProfile, Hibernate, PostgreSQL and the TomEE application server. It’s really easy and fun to develop Java EE 8 applications.
Tools You Will Need:
- Maven 3.3+
- JDK 1.8
- PostgreSQL
Note: We will not go through the process of how to install the needed tools in this tutorial.
Generate the Project
We will use the MicroProfile starter to generate our application. Go to start.microprofile.io and enter the details as follows:
groupId: org.superbiz artifactId: blog MicroProfile Version: 2.0.1 MicroProfile Server: Apache TomEE 8.0.0-M2 Examples for specifications: Uncheck all examples
Open pom.xml
and add the following dependencies to the <dependencies>
section:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-agroal</artifactId>
<version>5.4.3.Final</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.5</version>
</dependency>
We added Java EE 8, Hibernate and PostgreSQL dependencies. In the <properties>
section find the TomEE version and update it to 8.0.0-M3 and while we are at it change the tomeeClassifier
to plus
instead of microprofile
.
TomEE Config
It’s time to start the real coding, the first thing we will do is to configure the DataSource
. Create the resources.xml
file inside src/main/webapp/WEB-INF/
and make it look like this:
<?xml version="1.0" encoding="UTF-8"?>
<tomee>
<Resource id="jdbc/my_blog_datasource" type="javax.sql.DataSource">
JdbcDriver = org.postgresql.Driver
JdbcUrl = jdbc:postgresql://localhost/blog
UserName = mybloguser
Password = mypass
jtaManaged = true
</Resource>
</tomee>
This is the configuration for the database connection. Now create the persistence.xml
inside src/main/resources/META-INF/
and make it look like this:
<?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="myBlog_PU" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>jdbc/my_blog_datasource</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="tomee.jpa.factory.lazy" value="true" />
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL10Dialect" />
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform"/>
</properties>
</persistence-unit>
</persistence>
The 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, and how classes should be mapped to database tables.
We are done with the configurations and it’s time to start coding our API.
Creating Entities
Entities are POJOs (Plain Old Java Objects) class which are annotated so it can be easily persisted.
Create a new file called Post.java
inside entities
package and add the following:
package org.superbiz.blog.entities;
import javax.persistence.*;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.util.Date;
@Entity
@Table(name = "posts")
@NamedQueries({
@NamedQuery(name = "Post.findAll", query = "SELECT p FROM Post p")
})
public class Post implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "title", length = 255)
private String title;
@Column(name = "body", length = 1000)
@Size(min=10, max=1000)
private String body;
private Date createdAt;
private Date updatedAt;
private String author;
public static long getSerialVersionUID() {
return serialVersionUID;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public Date getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@PrePersist
private void onCreate() {
createdAt = new Date();
}
@PreUpdate
private void onUpdate() {
updatedAt = new Date();
}
}
@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 theId
property is also annotated with@GeneratedValue
to indicate that theId
should be generated automatically.@Size
annotation is a bean validation that validates that the value is between the attributemin
andmax
.@Column
annotation is used to specify the mapped column for a persistent property.
Business Logic
Create a new file called PostRepository
inside repositories
package and add the following:
package org.superbiz.blog.repositories;
import org.superbiz.blog.entities.Post;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;
@Stateless
public class PostRepository {
@PersistenceContext(unitName = "myBlog_PU")
EntityManager em;
public List getAllPosts() {
return em.createNamedQuery("Post.findAll", Post.class).getResultList();
}
public Post findById(Long id) {
return em.find(Post.class, id);
}
public void create(Post post) {
em.persist(post);
}
public void update(Post post) {
em.merge(post);
}
public void delete(Post post) {
if (!em.contains(post)) {
post = em.merge(post);
}
em.remove(post);
}
}
@PersistenceContext
annotation injects theEntityManager
to be used at runtime.getAll()
method retrieves all the posts from the database and return the entire list.findById()
method finds onePost
object from the database with ID and returns it.update()
method will update existingPost
object in the database.create()
method will createPost
object in the database.delete()
method will find thePost
bject in the database and delete it.
Resource
The next step is to create a resource class. Create a new file called PostResource.java
inside resources
package and move the BlogRestApplication.java
inside that package also and remove the HelloController.java
because we don’t need that.
package org.superbiz.blog.resources;
import org.superbiz.blog.entities.Post;
import org.superbiz.blog.repositories.PostRepository;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
@RequestScoped
@Path("posts")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class PostResource {
@Inject
PostRepository postRepository;
@GET
public Response getAllPosts() {
return Response.ok().entity(postRepository.getAllPosts()).build();
}
@GET
@Path("{id}")
public Response getPostById(@PathParam("id") Long id) {
return Response.ok().entity(postRepository.findById(id)).build();
}
@POST
public Response create(Post post, @Context UriInfo uriInfo) {
Post postId = postRepository.create(post);
UriBuilder builder = uriInfo.getAbsolutePathBuilder();
builder.path(Long.toString(postId.getId()));
return Response.created(builder.build()).build();
}
@PUT
@Path("{id}")
public Response update(@PathParam("id") Long id, Post post) {
Post updatePost = postRepository.findById(id);
updatePost.setTitle(post.getTitle());
updatePost.setBody(post.getBody());
updatePost.setAuthor(post.getAuthor());
return Response.ok().entity(post).build();
}
@DELETE
@Path("{id}")
public Response delete(@PathParam("{id}") Long id) {
Post post = postRepository.findById(id);
postRepository.delete(post);
return Response.noContent().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 intoPost
object.- We inject the
PostRepository
with the@Inject
annotation. @GET
annotation maps/posts
HTTP GET request togetAll()
method, which will retrieve all the posts 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.
Your directory structure should look like this:
$ tree . ├── pom.xml ├── readme.md └── src ├── main │ ├── java │ │ └── org │ │ └── superbiz │ │ └── blog │ │ ├── entities │ │ │ └── Post.java │ │ ├── repositories │ │ │ └── PostRepository.java │ │ └── resources │ │ ├── BlogRestApplication.java │ │ └── PostResource.java │ ├── resources │ │ ├── META-INF │ │ │ ├── microprofile-config.properties │ │ │ └── persistence.xml │ │ └── publicKey.pem │ └── webapp │ ├── WEB-INF │ │ ├── beans.xml │ │ └── resources.xml │ └── index.html └── test └── java
Test
Time to test our application. Open your terminal and navigate to the directory where you have the application and run the following command to build and start the TomEE application server:
$ mvn clean package && java -jar target/blog-exec.jar
Open a new terminal window and use curl
to test that everything works.
GET Request
$ curl -v http://localhost:8080/data/posts
Single GET Request
$ curl -v http://localhost:8080/data/posts/3
POST Request
$ curl --header "Content-Type: application/json" \ --request POST \ --data '{"title":"My First Blog Post","body":"Welcome to my first blog post, this blog runs on TomEE Application Server", "author": "Hayri Cicek"}' \ http://localhost:8080/data/posts
PUT Request
$ curl -X PUT -H "Content-Type: application/json" -d '{"title":"My Updated Blog Post","body":"Welcome to my Updated blog post, this blog runs on TomEE Application Server", "author": "Hayri Cicek"}' http://localhost:8080/data/posts/3
DELETE Request
$ curl -X "DELETE" http://localhost:8080/data/posts/3
As you can see, it’s really easy and fun to create REST API’s with Java EE 8 and running on TomEE Application Server.
Nice guide!
Hi,
Thanks for the great article.
I have some similar kind of requirement, please guide me is it possible or not and if possible please suggest how to achieve this.
I have created a spring boot project with JPA which running in TomEE with multiple databases( https://github.com/deepeshuniyal/JNDISpringBootTom8.git ), which is working fine.
Now I have to use TomEE JTA with multiple databases. commit will work with multiple databases in groups.
Hoping for your response.
Hi Deepesh,
Base on the context you provided, it seems like your scenario will require XA data sources [1] since you want to have two-phase commits with multiple databases.
We also invite you to join the TomEE community [2] to have a broader conversation.
[1] https://tomee.apache.org/tomee-8.0/docs/configuring-datasources-xa.html
[2] https://tomee.apache.org/community/contributing/contribution-tips.html