Skip to main content

Java EE Application Development – RESTful Web Service

Applications can use web services to share data, using common protocols and data structure. RESTful web services, the full name is Representational State Transfer, in which, data and functionality are considered resources and accessed by Uniform Resource Identifiers (URIs). In this tutorial, we are going to add the RESTful web services feature to our project and show how to generate JSON or XML data for sharing.

Source code on github: https://github.com/zxuqian/Learning-Java-EE-2016/tree/09f7cf7b123e9ed3029841df98db4f5cd42b55c4

Create module

Open IntelliJ, choose File -> New -> Module… menu and in the popup dialog, select Maven, parent select notebookRoot, set groupId to “com.zxuqian”, artifactId to notebookRESTful, click next, make sure the module directory is under the same level with other modules then click finish.

Create a folder named WebContent under the same level of src folder, inside it, create a WEB-INF folder, this is where the web.xml file lives and maven war plugin will treat it as context root folder. I will discuss it later.

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/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>notebookRoot</artifactId>
        <groupId>com.zxuqian</groupId>
        <version>0.0.2</version>
        <relativePath>../notebookRoot/pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>notebookRESTful</artifactId>
    <packaging>war</packaging>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
            </plugin>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <configuration>
                    <warSourceDirectory>WebContent</warSourceDirectory>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.jboss.spec.javax.ws.rs</groupId>
            <artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>javax.enterprise</groupId>
            <artifactId>cdi-api</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.jboss.spec.javax.ejb</groupId>
            <artifactId>jboss-ejb-api_3.2_spec</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.zxuqian</groupId>
            <artifactId>notebookService</artifactId>
            <type>ejb</type>
        </dependency>

    </dependencies>


</project>

Here a new artifact is imported, the org.jboss.spec.javax.ws.rs. This is the JBoss implementation of JAX-RS specification. All you need to implement web service is inside this library. The notebookService module is imported as well. We are going to use service to add a new user and get an existing user.

Coding

In the notebookRESTful module, create a Java class, UserResource under com.zxuqian.notebook.webservice package.

@Path("/user")
public class UserResource {

    private static final Logger logger = Logger.getLogger(UserResource.class.getCanonicalName());

    @EJB
    private IUserServiceLocal userService;

    @GET
    @Path("/{id}")
    @Produces({MediaType.APPLICATION_JSON})
    public User getUserById(@PathParam("id") Long id) {

        User user = this.userService.getUserById(id);
        return user;

    }

    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    public Response createUser(User user) {
        this.userService.addUser(user);

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

    @DELETE
    @Path("/{id}")
    public Response deleteUser(@PathParam("id") Long id) {

        logger.severe("The id is: " + id);

        User user = this.userService.getUserById(id);

        logger.severe("The user is: " + user);

        this.userService.deleteUser(user);

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


}
  • @Path on the class means the root section of the URI that this class is mapped to. For example, the URI to access the web service is http://localhost:8080/notebook-rest, then the URI for accessing user resource will begin with http://localhost:8080/notebook-rest/user. @Path on the method indicating the URI section for specific operations. If you want to get a user according to the user id, then you will use http://localhost:8080/notebook-rest/user/1 and it will map to the getUserById method. The {id} variable in @Path("/{id}"} will be replaced by the actual value, 1 e.g., and it is referenced by the @PathParam("id") parameter annotation. The id will be assigned the value 1 automatically.
  • There are seven HTTP verbs in RESTful web services that define different operations to a resource. The annotations in Java EE have the same name with those verbs. @PUT is to create a new resource, @DELETE is to delete a resource, @GET is to get a resource, @POST is to update a resource.
  • @Consume and @Produce means what type of content this method is going to consume and produce. Here getUserbyId() will produce json content and createUser will consume json content.
  • As you can see, the deleteUser() method will first find the user by id, then delete it. Actually, the user object returned from getUserById() method is a detached object, you can’t delete the detached object in JPA, so you need to add user = this.entityManager.merge(user); in the deleteUser() method in UserDao in notebookDomain module, this will merge the detached object to the persistent state:
public void deleteUser(User user) {
        user = this.entityManager.merge(user);
        this.entityManager.remove(user);

}

The code for each method is simple and intuitive. Note the deleteUser and createUser methods return a Response object, which is a 200 code, representing action success.

JAXB

JAXB is Java API for XML binding, that let us use annotations to mark the POJO and generate XML or JSON structure. We will update the User class in notebookDomain class to make it a JAXB model. Simply add a @XmlRootElement on the class level, and it will use the same variable names in your class as the XML elements and use the class name as the XML root element.

User.java

@Entity
// 'from' unexpected error. Add JPA facet by project structure, then specify the persistent.xml and provider.
@NamedQuery(name = "getAllUsersQuery", query = "from User u")
@XmlRootElement
public class User implements Serializable {

Configure Module

Now create a web.xml file under WebContent/WEB-INF folder with the following code:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">

  <servlet-mapping>
    <servlet-name>javax.ws.rs.core.Application</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>

</web-app>

The javax.ws.rs.core.Application is a servlet that maps the URL to the web service. Here /* means all paths will go through this servlet and mapped to web service URIs.

In the pom.xml of notebookEAR module, configure the context root for the web service module (Full code can be found on GitHub):

<webModule>
      <groupId>com.zxuqian</groupId>
      <artifactId>notebookRESTful</artifactId>
      <contextRoot>/notebook-rest</contextRoot>
</webModule>

Running the Example

Run maven install lifecycle goal on notebookRoot, then run wildfly:run plugin goal on notebookEAR module, to start wildfly server and deploy the ear file.

Here I use a test tool called Postman you can download it here: https://www.getpostman.com/. After download it, open it, the application looks like this:

 

In the right side, you can choose the HTTP verb and enter the URI to a specific resource, then click Send. It will emulate an HTTP request to your web service. Here I’m accessing the user with id 1, and the returned result is a JSON data. (For test purpose, the password is displayed here, you should never do that in the production mod)

To add a user:

 

Choose PUT HTTP verb. Select Body tab, and under that, select JSON(application/json) content type, the orange color. Then you copy the structure you get from the GET method, and delete the id attribute, change other attributes, and click Send. If it succeed, you will see the 200 Status code at the bottom middle right.

The result of database query:

 

A user with id 5 is added to the database.

To delete a user:

 

 

Choose DELETE HTTP verb, specifiy the URI, then click Send button. Here I’m deleting the user just inserted to the database. After you see the 200 status code, you can check your database to see the result:

 

Finally, if you change the @Produces annotation on the getUserById method in UserResource class, it will produce XML data:

 

Now you may have learned the most basic web service knowledge, if you have any questions, feel free to comment below, I’m glad to help!

  • IctDynamic

    https://uploads.disquscdn.com/images/5b91a34cd0a9b9816fbfcf893e73d97ea544e2a87994df661954baef42a46054.png Interesting article but your HTTP statuses don’t correspond well with the statuses that are ‘typically’ used. Creation of a resource should result rather in a 201 status code and a PUT, DELETE or PATCH should rather result in a 204 status code (no content).

    In addition, please find below a tip with regards to the usage of Postman. One can easily include test with Postman and can bundle execution of requests in a collection. Please find screenshot of such a test below. All the best from hellhole Belgium.

    • Yes, you are absolutely correct about the HTTP status code. As this tutorial belongs to beginner series, I didn’t consider that very well. I will make explanations in future blogs and, I will learn Postman advanced usages as well. Thank you so much for your advice and information!