First functional example
Now that we have our development environment all set up, it is time to get your hands dirty and write the first RESTful web service. As we are using JBoss, let's use the RESTEasy implementation for JAX-RS. We will develop a very simple example; let's imagine you want to implement a service to save and search for people's information.
First, we create a simple Person
domain class that uses JAXB annotations. JAXB marshals/unmarshals objects between XML and Java. For this example, we'll store these instances in an in-memory cache instead of a database. In JEE, this typically represents a table in a relational database, and each entity instance corresponds to a row in that table, as presented in the following code:
package com.packtpub.resteasy.entities; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "person") @XmlAccessorType(XmlAccessType.FIELD) public class Person { @XmlAttribute protected int id; @XmlElement protected String name; @XmlElement protected String lastname; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getLastname() { return lastname; } public void setLastname(String lastname) { this.lastname = lastname; } }
Next, we create a new class called PersonService
in the com.packtpub.resteasy.services
package. This class will have two methods; one to register a new person and another to search for people by ID. This class will store people using an in-memory map cache.
The service will have the following implementation:
package com.packtpub.resteasy.services; import java.net.URI; import java.util.HashMap; import java.util.Map; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; import com.packtpub.resteasy.entities.Person; @Path("/person") public class PersonService { private Map<Integer, Person> dataInMemory; public PersonService() { dataInMemory = new HashMap<Integer, Person>(); } @POST @Consumes("application/xml") public Response savePerson(Person person) { int id = dataInMemory.size() + 1; person.setId(id); dataInMemory.put(id, person); return Response.created(URI.create("/person/" + id)).build(); } @GET @Path("{id}") @Produces("application/xml") public Person findById(@PathParam("id") int id) { Person person = dataInMemory.get(id); if (person == null) { throw new WebApplicationException(Response.Status.NOT_FOUND); } return person; } }
The @Path
annotation defines the path in the URL that will be available on the functionalities that have been written within this class. The method annotated with @Post
indicates that it should make a HTTP POST request. Furthermore, it is annotated with @Consumes
and uses the application
/xml
value; this means that the POST request will be performed with a string in XML format, containing the information of the person to be saved. On the other hand, to find a person from its ID, you must make an HTTP GET request. The URL must indicate the ID the same way as indicated by the @Path
annotation on the method. The @Produces
annotation indicates that we will get the response in XML format. Finally, notice that the parameter ID, as indicated in the @Path
annotation, is used as an argument of the method using the @PathParam
annotation.
Finally, we write a class that will extend the Application
class and set the service we just created as a singleton. So, the information won't get lost in every request, and we will keep it in memory as follows:
package com.packtpub.resteasy.services; import java.util.HashSet; import java.util.Set; import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; @ApplicationPath("/services") public class MyRestEasyApplication extends Application { private Set<Object> services; public MyRestEasyApplication() { services = new HashSet<Object>(); services.add(new PersonService()); } @Override public Set<Object> getSingletons() { return services; } }
Note that as we have mapped our entity using JAXB, our methods consume and produce information in the XML format.
In order to deploy our application in JBoss, we should add a dependency in the pom.xml
file. This dependency must reference to the JBoss plugin. We have to change the generated artifact name in pom.xml
. The default value for this is the artifactId
file, followed by the version; for example, resteasy-examples-1.0-snapshot.war
. We will set it, so we will use just the artifactId
file; in this case, resteasy-examples.war
. All of these configurations must be included, modified, and implemented in pom.xml
, as shown in the following piece of XML code:
<build>
<finalName>${artifactId}</finalName>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.jboss.as.plugins</groupId>
<artifactId>jboss-as-maven-plugin</artifactId>
<version>7.5.Final</version>
<configuration>
<jbossHome>/pathtojboss/jboss-as-7.1.1.Final</jbossHome>
</configuration>
</plugin>
...
</plugin>
</plugins>
</pluginManagement>
</build>
You should change the value of the jbossHome
property for the path of your JBoss installation. After this, we will use the command terminal; head to the project's directory, and type mvn jboss-as:run
. If you make any change on the code after the command has been executed, then you should use the following command in order to see the changes:
mvn jboss-as:redeploy
Run and redeploy are the goals of this plugin. If you want to know more goals about this plugin, you can visit https://docs.jboss.org/jbossas/7/plugins/maven/latest/). This will compile all project classes again; it will then be packaged in order to create the .war
file. At the end, the modifications will be deployed on the server. If everything is okay, we should see a message in the terminal saying that the deployment has been done successfully, as shown in the following screenshot:
The source code of this chapter is available on GitHub at the following location:
https://github.com/restful-java-web-services-security/source-code/tree/master/chapter01
Testing the example web service
At this moment, we will test the functionality we just created. We will use SoapUI as our test tool; make sure you use the latest version, or at least the version equal to or greater than 4.6.x because this version offers more features to test the RESTful Web services. Let's start by performing the following steps:
- From the main menu, let's create a new REST project by navigating to File | New REST Project, as shown in the following screenshot:
- Set the URI of our service, as follows:
- After this, let's create a new person using the
POST
method from workspace. In the field Media Type, select application/xml and perform a request with a string that contains the XML with the information, as shown in the following text:<person><name>Rene</name><lastname>Enriquez</lastname></person>
- When we click on the Play button, we should obtain an answer where it shows the created resource URI (hyperlink "
http://localhost:8080/resteasy-examples/services/person/1
"), as shown in the following screenshot: - If we change the URI from the Resource textbox in SoapUI and use the
GET
method, it will show us the data we just entered, as shown in the following screenshot:
Congratulations! We have developed our first functional RESTful web service with two features. The first is to keep people's information in memory, and the second is to retrieve people's information through an ID.
Note
If you restart JBoss or deploy the application again, all data will be lost. Before searching for people's information, you must first save the data.