Tuesday, April 29, 2014

RESTful Web Services with Java JAX-RS using Jersey and Eclipse - Tutorial

This tutorial shows how to create RESTful web services in Java using Eclipse and Jersey.

REST (Representational State Transfer) is an architectural style based on the HTTP protocol where resources are identified by global IDs (typically using URIs). REST client applications use HTTP methods (GET/ POST/ PUT/ DELETE) to access the service's resources.

RESTful web services are based on HTTP methods and the concept of REST. A RESTful web service should define the base URI for the service, the supported MIME types for the response data (text, XML, JSON,..), and the supported set of operations (GET/ POST/ PUT/ DELETE) of the service.

The Java API for RESTful Web Services (JAX-RS) is an annotation-based API for implementing RESTful web services based on the  HTTP protocol. This is defined in the Java Specification Request (JSR) 311. Jersey is a JAX-RS reference implementation and provides it's own API with additional features and utilities.

JAX-RS also supports the creation of XML and JSON via the Java Architecture for XML Binding (JAXB).


JAX-RS annotations

@Path(/your_resource_path) - sets the path to the base URI + /your_resource_path. The base URI consists of your host, port, any context(project name), and the servlet's url-pattern(eg.; /rest) from the web.xml configuration file.

This tutorial's base URI, for example, is   http://localhost:8080/RESTfulWSDemo/rest
       
@GET - indicates that the annotated method will be invoked by a HTTP GET request   
@PUT - indicates that the annotated method will be invoked by a HTTP PUT request
@POST - indicates that the annotated method will be invoked by a HTTP POST request
@DELETE - indicates that the annotated method will be invoked by a HTTP DELETE request    
@Produces - defines the MIME media type a resource can produce and send back to the client
@Consumes - defines which MIME type is consumed by the method
@PathParam - is used in the method's arguments to set the value of the URI parameters into the methods arguments
@QueryParam - is used in the method's arguments to set the value of the query parameters into the methods arguments.

Query Parameters are the parameters in the http url in the format of a query string where all parameters appear in the end of the url after the '?' symbol and parameters are separated with the '&' symbol
e.g.  http://localhost:8080/RESTfulWS/rest/demo?employeeId1=10&employeeId2=20

Here are the Java JAX-RS and Jersey JAX-RS documentation for a complete listing and description of available annotations and applications.


Development Environment:
1. Eclipse IDE for Java EE Developers 4.3.2  (Kepler)  download
2. Jersey 2.7  download
3. JDK 1.7  download
4. Tomcat 7

This tutorial assumes that you have the Java JDK installed in your machine. You should also have Eclipse installed and configured with  a Tomcat 7 application server.


1. Create a Dynamic Web Project in Eclipse

Set your Eclipse view to Java EE perspective then click on:

File > New > Dynamic Web Project

You will get the shown page below.




For 'Project name':
Enter your project name such as "RESTfulWSDemo". This will be the context root of your application.

For 'Target runtime':
Select 'Apache Tomcat v7.0' or your desired server.

For 'Dynamic web module version':
Select the servlet version you will use. If you are using Java EE 6 or 7, select '3.0'.  If you are using Java EE 5, select '2.5' or lower.

You can see the Servlet mapping with JDK and Tomcat versions from the Tomcat-Servlet-JDK mapping page.

For 'Configuration':
Default Configuration is fine.


Click on 'Next' button

You will get the page shown below.



You don't need to do anything on this page.

Click on 'Next' button

You will get the page shown below.



Check the box for 'Generate web.xml deployment descriptor'.

Click on 'Finish' button.


2. Download Jersey and copy Jersey jars to project's lib folder

Unzip the downloaded Jersey zip file to your local directory.

Copy all the jar files from Jersey's  api, ext and lib folders to your projects  WebContent/WEB-INF/lib  folder.



3. Create your Java class

Right-click on Java Resources/src  folder.

Select New > Class

You will get the page shown below.



Enter your package name and the class name.

Click 'Finish".

Complete your new class with the following code:

package com.ericsoriano.restwebservice;

import javax.ws.rs.GET;
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;

// @GET annotation registers the method to answer to a HTTP GET request
// @Produces annotation defines which MIME type is delivered by a method annotated with @GET
// @Produces can deliver text, XML, HTML

// The browser requests the HTML MIME type by default

// @Path annotation exposes resource (class and methods) to the client thru base URI + path

// URI = (context root)/(url-pattern in your web.xml's servlet mapping)/(path defined in your @Path annotation)  eg.;   RESTfulWSDemo/rest/demo

// URI parameter values are assigned to variables thru the methods's @Path annotation by enclosing the variables within curly braces "{}" eg.;   @Path("/add/{n1}/{n2}")

// @PathParam annotation is used in the method's signature to set the value of the parameter into the methods arguments
// eg.;  public String add(@PathParam("n1") int n1, @PathParam("n2") int n2)



// This class resource's URI effectively becomes "RESTfulWSDemo/rest/demo" thru the @Path annotation
@Path("/demo")
public class JerseyRESTWSDemo {

   // This method is called if client requests for HTML 
   @GET
   @Produces(MediaType.TEXT_HTML)
   public String serveHTML() {
    return "<html> " + "<title>" + "Jersey REST Demo" + "</title>"
         + "<body><h1>" + "Jersey REST Web Service works!" + "</body></h1>" + "</html> ";
   }

   // This method is called if client requests for TEXT_PLAIN 
   @GET
   @Produces(MediaType.TEXT_PLAIN)
   public String serveText() {
    return "Jersey REST Web Service works!";
   }

   // This method is called if client requests for XML 
   @GET
   @Produces(MediaType.TEXT_XML)
   public String serveXML() {
    return "<?xml version=\"1.0\"?>" + "<message> Jersey REST Web Service works!" + "</message>";
   }
 
   @PUT
   @Path("/{employeeId}")
   @Produces(MediaType.TEXT_PLAIN)
   public String updateInfo(@PathParam("employeeId") String employeeId) {

    // CODE TO UPDATE EMPLOYEE RECORD GOES HERE
        
    return "Employee " + employeeId + " record is updated!";        
   
   }
   
   @GET
   @Path("/add/{n1}/{n2}")
   @Produces(MediaType.TEXT_HTML)
   public String add(@PathParam("n1") int n1, @PathParam("n2") int n2) {
    String output = "The sum of " + n1 + " and " + n2 + " is " + (n1 + n2);
    return "<html> " + "<title>" + "Jersey REST Demo" + "</title>"
         + "<body><h1>" + output + "</body></h1>" + "</html> ";
   }
}





4. Define the Jersey servlet dispatcher in your web.xml

You need to direct all the REST requests to the Jersey container by defining a servlet dispatcher in the application's web.xml file.

Modify the default web.xml created by Eclipse with the code below.

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>RESTfulWSDemo</display-name>
  <servlet>
    <servlet-name>Jersey REST Service</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>jersey.config.server.provider.packages</param-name>
      <param-value>com.ericsoriano.restwebservice</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Jersey REST Service</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>
</web-app>
 


NOTE: The values for the <servlet-class> and <param-name> are specifications for Jersey 2.0 and higher (Jersey 2.7 as of this writing).

The parameter <param-value>com.ericsoriano.restwebservice</param-value> defines the package Jersey will look at for the web service classes. This property must point to the package of your Java resource classes.

The <url-pattern>/rest/*</url-pattern> defines the base URL pattern to build the URL for your application's rest service classes.


5. Test the RESTful Web Service

Start your RESTful web service application by:

Right-click on project name > Run As > Run on Server

The URL consists of your host, port, context(project name), the servlet's url-pattern(eg.; /rest) from the web.xml configuration file, the /demo @Path annotation on your class file, and any @Path annotation on your methods (eg., /add/10/5)(see second test URL below).    


Test the REST service by typing the following URLs in the browser:

http://localhost:8080/RESTfulWSDemo/rest/demo

Returns this response on the browser:  Jersey REST Web Service works!

See browser screenshot below:





http://localhost:8080/RESTfulWSDemo/rest/demo/add/10/5

Returns this response on the browser:  The sum of 10 and 5 is 15

See browser screenshot below:




Saturday, April 26, 2014

How to Create a Web Application Project with Maven in Eclipse

In this tutorial, we will see how to create a web application in Eclipse using Maven's m2eclipse plugin. The m2eclipse plugin comes with the Eclipse IDE version 4.3.2.

Tools used:
1. Eclipse IDE for Java EE Developers 4.3.2   (Kepler)
2. Tomcat 7
3. JDK 1.7
4. Maven Eclipse Plugin - m2eclipse version 1.4


1. Create the Maven project in Eclipse

Click on File > New > Project > Maven > select Maven Project > click Next button





You will now get the screen below. Just check the box for 'Use default Workspace location' if it's not checked by default. Click the 'Next' button.





You will now get the screen below. You will need to select an archetype. An archetype is just ta template that Maven will use for your new web application project.

Enter 'webapp' into the filter textbox and select 'maven-archetype-webapp' from the list.

Click the 'Next' button.





You will now get the screen below. You need to enter your maven project's group Id, Artifact Id, Version and Package information. The 'Artifact Id' is your project's name.




Click the 'Finish' button. This will create your Maven project in eclipse.
You should now see the new project in the Package Explorer.



2.  Add the 'Server Runtime' library in the project's  'Java Build Path'  property.

Right-click on the project name > Properties > Java Build Path




Click on Add Library > select Server Runtime > select a servlet container (eg.; Apache Tomcat) > click on Finish.

You will be back on the screen above.

Click on Ok.

Eclipse should then automatically take the servlet container's libraries into the build path.

You should now see the servlet container library (eg.; Apache Tomcat library) in your projects directory.
You should also now see the following source folders created under your project's directory.

  • src/main/java
  • src/test/java

If it was not created, you may manually create it.



3.  Add or change (optional)  the 'JRE System Library' in the project's  'Java Build Path'  property.

Note that the list of libraries on the Java Build Path now shows Apache Tomcat (the Server Runtime library we added in the previous step).

You may now change the JRE System Library (optional - only if you want to) or add a JRE System Library if the  Java Build Path does not have one yet.

Right-click on the project name > Properties > Java Build Path 




Click on Add Library > select JRE System Library > click Next > choose your JRE (eg.; Workspace default JRE or Alternate JRE) > click on Finish.


Running this project in its bare form should give you the 'Hello World' webpage from index.jsp. Try it.

That's it. Your Maven web project in eclipse is now ready. You can now start adding dependencies and code to your project.

Override equals and hashCode methods in Java

Theory

equals() and hashCode() methods are defined in the Object class. So all Java objects inherit a default implementation of these methods.

The default implementation of the equals() method (javadoc) actually is the same as the “==” operator. It checks to see if both objects reference the same memory location. But, the equals method is meant to compare the contents of 2 objects, and not their location in memory. So when overriding the equals() method, you should compare the values of the objects instead.

The equals() method must be consistent (if the objects are not modified, then it must keep returning the same value).

The hashCode() method (javadoc) must also be consistent (if the object is not modified in terms of equals(), it must keep returning the same value).

The relation between the two methods is:

Whenever a.equals(b), then a.hashCode() and b.hashCode() must produce the same integer result.

The general contract for the hashCode method states that equal objects must have equal hash codes.


Practice

If you override the equals method, then you must override the hashCode method.

Use the same set of the object's attributes (fields) in the equals and hashCode method's code.

Use the EqualsBuilder and HashCodeBuilder helper classses from   Apache Commons Lang.

Below is a usage example:

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

public class Employee {
 
   private Integer id;
   private String firstname;
   private String lastname;
   private int age;
   //...

   @Override 
   public int hashCode() {
      // you pick a hard-coded, randomly chosen, non-zero, odd number as args
      // ideally different for each class
      return new HashCodeBuilder(17, 37).
      //use next line only if you want to inherit hashCode behavior from superclass
      //appendSuper(super.hashCode()).
      append(id).
      append(firstname).
      append(lastname).
      toHashCode();
   } 

   @Override
   public boolean equals(Object obj) {
      if (obj == this)
         return true;
      if (obj == null)
         return false; 
      if (obj.getClass() != getClass())
         return false;  
     
      Employee rhs = (Employee) obj;
      return new EqualsBuilder().
      //use next line only if you want to inherit equals behavior from superclass
      //appendSuper(super.equals(obj)).
      append(this.id, rhs.id).
      append(this.firstname, rhs.firstname).
      append(this.lastname, rhs.lastname).
      isEquals();
   }
 
} 



You can also use Eclipse to generate the two methods for you:

Right click on class from editor pane > source > Generate hashCode() and equals()


Note when using in ORM

If you will use the object in ORM, always use getters instead of field references in your hashCode() and equals() methods.  The reason is that when fields are lazy-loaded, the field values are not available until their getter methods are called. In this case, the value may be null and lead to incorrect behavior.



Friday, April 18, 2014

Resolving "HttpServletRequest cannot be resolved" error in eclipse

Eclipse errors like - "The import javax.servlet.http.HttpServletRequest cannot be resolved" are caused by not having the servletcontainer-specific libraries in your project's build path.

You should at least use the Eclipse IDE for Java EE Developers.

You should also have a servlet container (eg.; Tomcat, Glassfish) installed on your machine.

These are what you have to do in your project if you haven't done so:

1. Integrate a new servlet container in Eclipse.

Open the Servers view (if not yet opened in the bottom box section of Eclipse).

Right-click from the Servers pane  > New >  Server.

A new window will pop up. Pick the servlet container you want to use from the list and walk through the wizard.


2.  Set the project's  'Targeted Runtimes'  property.

Right-click on the project name > Properties > Targeted Runtimes.

Select a servlet container (eg.; Apache Tomcat) and click "OK".

Eclipse should then automatically take the servlet container's libraries into the build path. Build your project and the errors should go away. The errors are resolved.

If the error persists, then for some reason the servlet container's libraries was not automatically added into the build path. Just do the next step.


3. Manually add the servlet container's library into the build path.

Right-click on the project name > Properties > Java Build Path > Add Library > Server Runtime > select a servlet container (eg.; Apache Tomcat) > Finish.

Build your project and the errors should go away. The errors are resolved.


IMPORTANT NOTES:
Some examples of servlet container-specific libraries are servlet-api.jar, el-api.jar, javaee.jar, annotations-api.jar, etc.

Never manually copy or move servlet container-specific libraries into your webapp's /WEB-INF/lib and JRE/lib.

Servlet container libraries belong only in the servlet container. For example, in your webapp,  the Apache Tomcat jars should only be in  /Java Resources/Libraries/Apache Tomcat folder.

You should also never have a duplicate servlet container in the classpath.




Monday, April 14, 2014

How to install Maven on Windows

Maven is a build and dependency management tool for java based application development.

It is not installed as a windows service. It is just configured with the windows environment variables. You just need to download the Maven binary zip file, extract it and configure the Windows environment variables.

The Windows Environment Variables are accessed from this location:

Click on Windows 'Start' button  >  Right-click on 'Computer'  >  Properties  >  Advanced system setting  >  Environment Variables

STEPS:

1. Set the JAVA_HOME system variable

Make sure the JDK is installed and "JAVA_HOME" system variable is present in the Windows environment variables. This should have the path to the jdk folder.




2. Download Maven

Download Maven from the Apache Maven download page. Choose a version and pick a binary distribution (e.g.;  apache-maven-3.2.1-bin.zip).


3. Extract Maven 

Extract the zip file to a folder and make note of the directory path.


4. Set the M2_HOME system variable

Add the M2_HOME system variable and it should point to the Maven folder. Other people use MAVEN_HOME as the variable name but the maven installation instructions (at least as of version 3.2.1) specifically instructs to use M2_HOME as the variable name. One reason may be that M2_HOME is also the variable name used in the maven batch file (mvn.bat). Go open the batch file (found in the bin folder) and see.




5. Update the PATH system variable with the path to Maven's bin folder

Edit the Path system variable and add the entry " %M2_HOME%\bin " to point the Path variable to Maven's bin folder. This setting will allow you to run maven's command anywhere.




Click 'OK' to apply the new settings.


6. Verify your Maven installation is working

Open a new command prompt and type "mvn --version".

C:\Users\Eric>mvn --version
Apache Maven 3.2.1 (ea8b2b07643dbb1b84b6d16e1f08391b666bc1e9; 2014-02-14T09:37:52-08:00)
Maven home: C:\_java\apache-maven-3.2.1
Java version: 1.7.0_51, vendor: Oracle Corporation
Java home: C:\Program Files\jdk1.7.0_51\jre
Default locale: en_US, platform encoding: Cp1252
OS name: "windows 7", version: "6.1", arch: "amd64", family: "windows"

You should get a response similar to this to indicate a successful installation of Maven.