Restful Java Web Services
Content
REST
architecture
Java APIs for
JSON Processing
JAX-RS API
RESTful web service with JAX-RS
REST
architecture
Introduction
Representational State Transfer (REST)
Described in Roy Fielding's PhD dissertation
REST is not an architecture; rather, it is a set of constraints that creates a software
architectural style
Constraints
that define a
RESTful system
Client-server
Stateless
Cacheable
Uniform interface
Layered system
Code on demand
Client-server
Client does not need to know the implementation details in the server and the server is not worried about how the data is used by the client.
Stateless
Each request should be independent of the others.
Cacheable
Support a caching system in order to avoid repeated round trips.
Uniform interface:
Each resource exposed for use by the client must have a unique address and should be accessible through a generic interface.
Layered system
Helps to improve scalability by enabling load balancing, and also improves performance by providing shared caches at different levels.
Code on demand
Is optional, and indicate that the functionality can be extended at runtime.
Text
Therefore, a RESTful system can be implemented in any available networking architecture. More importantly, there is no need for us to invent new technologies or networking protocols.
Hypertext Transfer Protocol (HTTP) is the foundation of data communication
for WWW.
This protocol defines how messages are formatted, transmitted, and
processed over the Internet.
HTTP versions
HTTP/0.9 - Released in 1991, very primitive and supported only the GET method
HTTP/1.0 - Released in 1996, supported more request methods such as GET, HEAD, and POST
HTTP/1.1 - Released in 1999, This was the revision of HTTP/1.0. This version is in common use today
HTTP/2 - Released in 2015, Mainly
focused on how the data is framed and transported between the client and the server
HTTP
request-response
model
URI: Uniform resource identifier
Is a text that identifies any resource or name on the Internet.
One can further classify a URI as a Uniform Resource Locator (URL) if the text used for identifying the resource also holds the means for accessing the resource such as HTTP or FTP
HTTP request methods
CRUD in REST
Content types
The Internet media type (also known as the MIME type) indicates the type of data that a file contains.
text | Indicates that the content is plain text. Also have some subtypes (text/html) |
---|---|
multipart | Consists of multiple parts of the independent data types. Used for submitting forms with multiple data. (multipart/formdata) |
message | Allows messages to contain other messages or pointers to other messages.(message/partial) |
image | Represents the image data. (image/png) |
audio | Indicates the audio data. (audio/mpeg) |
video | Indicates the video data. (video/mp4) |
application | Represents the application data or binary data. (application/json; charset=utf-8) |
HTTP status codes
1xx Informational:
This series of status codes indicates informational content. This means that the request is received and processing is going on.
2xx Success:
This series of status codes indicates the successful processing of requests
3xx Redirection:
This series of status codes indicates that the client needs to perform further actions to logically end the request.
4xx Client Error:
This series of status codes indicates an error in processing the request.
5xx Server Error:
This series of status codes indicates server failures while processing a valid request.
Frameworks for building
RESTful web services
The Java API for RESTful web services (JAX-RS) is the Java API for creating RESTful web services, and also is a part of the Java Platform Enterprise Edition (Java EE)
Most popular implementations
Jersey and Apache CXF, are not just limited to reference implementations of the JAX-RS specifications, but they also offer many additional features on top of the specifications.
Java APIs for
JSON Processing
Understanding JSON
Processing
XML and JSON are the two most popular formats used by RESTful web services today.
JSON is a lightweight, text-based, platform neutral, data interchange format
in which objects are represented in the attribute-value pair format.
Historically,
JSON originated from JavaScript.
Sintax
An unordered collection of name-value pairs
(representing an object)
An ordered collection of values
(representing an array)
Each name:value pair in a JSON object is separated by a comma (,). The entire object is enclosed in curly braces ({ }).
{
"departmentId":10,
"departmentName":"IT",
"manager":"John Chen"
}
Arrays are enclosed in square brackets ([ ]), and their values are separated by a comma (,).
{
"departmentName":"IT",
"employees":[
{"firstName":"John", "lastName":"Chen"},
{"firstName":"Ameya", "lastName":"Job"},
{"firstName":"Pat", "lastName":"Fay"}
],
"location":["New York", "New Delhi"]
}
Basic data Types
Number | This type is used for storing a signed decimal number that may optionally contain a fractional part. |
---|---|
String | This type represents a sequence of zero or more characters. |
Boolean | This type represents either a true or a false value. |
Array | This type represents an ordered list of zero or more values, each of which can be of any type. |
Object | This type is an unordered collection of comma-separated attributevalue pairs enclosed in curly braces. |
null | This type indicates an empty value, represented by using the word null. |
Basic data Types
Number | |
---|---|
String | |
Boolean | |
Array | |
Object |
|
null |
{"totalWeight": 123.456}
{"firstName": "Jobinesh"}
{"isValidEntry": true}
{"fruits": ["apple", "banana", "orange"]}
{"departmentId":10,
"departmentName":"IT",
"manager":"John Chen"}
{"error":null}
Processing JSON data
Processing, we mean reading, writing, querying, and modifying JSON data.
Two widely adopted programming models for processing JSON
Object model
Streaming model
The entire JSON data is read into memory in a tree format
Means that data can be
read or written in blocks
Data is huge in size and it is not feasible to load the entire content into the memory
Partial processing is needed and the data model is not fully available yet
Java-based frameworks for processing JSON
JSR 353
Jackson
Gson
Jackson API
Tree model APIs:
This method provides APIs for building a tree
representation of a JSON document
Data binding API:
This method provides APIs for converting a JSON
document into and from Java objects
Streaming API:
This method provides streaming APIs for reading and
writing a JSON document
Jackson provides the following three alternative methods for processing JSON:
Is a multipurpose data processing Java library. The primary capability of this
tool is the support for processing JSON
Tree model
/*Other imports are removed for brevity*/
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
// Read in the JSON employee array form emp-array.json file
InputStream inputStream = getClass().getResourceAsStream("/emp-array.json");
//Create ObjectMapper instance
//ObjectMapper provides functionality for creating tree
//structure for JSON content
ObjectMapper objectMapper = new ObjectMapper();
//Read JSON content in to tree
JsonNode rootNode = objectMapper.readTree(inputStream);
//Check if the json content is in array form
if (rootNode.isArray()) {
//Iterate over each element in the array
for (JsonNode objNode : rootNode) {
//Find out the email node by traversing tree
JsonNode emailNode = objNode.path("email");
//if email is null, then update with
//a system generated email
if(emailNode.textValue() == null ){
String generatedEmail=getSystemGeneratedEmail();
((ObjectNode)objNode).put("email", generatedEmail );
}
}
}
//Write the modified tree to a json file
objectMapper.writeValue(new File("emp-modified-array.json"),
rootNode);
if(inputStream != null)
inputStream.close();
This example generates a tree hierarchy for the JSON array of employee objects and then queries the generated tree for the employee nodes with the null email value.
This example updates all the null email values with the system-generated e-mail addresses for later processing.
Data binding
String jsonString = "{\" firstName\":\"John\",\"lastName\":\"Chen\"}";
ObjectMapper objectMapper = new ObjectMapper();
//properties will store name and value pairs read from jsonString
Map<String, String> properties =
objectMapper.readValue(
jsonString, new TypeReference<Map<String, String>>() { }
);
Data binding is used to convert the JSON representation into and from Plain Old Java Object (POJO) by using property accessors or annotations. With this API, you can either generate generic collection classes or more specific Java objects
Simple Jackson data binding with generalized objects
Sometimes, you may need to deal with highly dynamic JSON content where you may not be able to map data to a specific Java object as the structure of the data changes dynamically.
Data binding
/*This example calls readValue(InputStream src, Class<T> valueType) on ObjectMapper to get the Java representation
of the JSON content*/
// emp.json file has following contents:
//{"employeeId":100,"firstName":"John","lastName":"Chen"}
ObjectMapper objectMapper = new ObjectMapper();
Employee employee = objectMapper.readValue(new File("emp.json"),Employee.class);
/*The next example demonstrates how you can create a Java collection containing the Employee objects from a
JSON array of employees.*/
ObjectMapper objectMapper = new ObjectMapper();
CollectionType collectionType = objectMapper.getTypeFactory().constructCollectionType(List.class, Employee.class);
//"emp-array.json" file contains JSON array of employee data
List<Employee> emp = objectMapper.readValue(new File("emp-array.json"), collectionType);
/*To convert a Java object into the JSON representation, you can call the
writeValue(OutputStream out, Object value) method on ObjectMapper. */
//Get the employee object
Employee employee = getEmployeeEntity();
//Convert the object in to JSON and write to a file
objectMapper.writeValue(new File("emp.json"), employee);
If the JSON data format, which a client receives, is well structured, you can directly map the content to a concrete Java class.
Full Jackson data binding with specialized objects
All names present in a JSON object need to match with the Java class properties for the default mapping mechanism to work
However, you can override the default mapping behavior by annotating a desired field (or by the getter and setter methods) with @JsonProperty
http://wiki.fasterxml.com/JacksonAnnotations
Streaming APIs
The following table lists important classes in the streaming model API
Class | Description |
---|---|
com.fasterxml.jackson.core.JsonParser | This class is used for reading the JSON content. |
com.fasterxml.jackson.core.JsonGenerator | This class is used for writing the JSON content. |
com.fasterxml.jackson.core.JsonFactory | This is the main factory class of the Jackson package. It is used to generate JsonParser and JsonWriter. |
Streaming APIs
Streaming APIs to parse JSON data
//Step 1: Finds a resource with a given name.
InputStream inputStream = getClass().getResourceAsStream("/emp-array.json");
//Creates Streaming parser
JsonParser jsonParser = new JsonFactory().createParser(inputStream);
//Step 2: Start parsing the contents
//We will use data binding feature from ObjectMapper
//for populating employee object
ObjectMapper objectMapper = new ObjectMapper();
//Continue the parsing till stream is opened or
//no more token is available
while (!jsonParser.isClosed()) {
JsonToken jsonToken = jsonParser.nextToken();
// if it is the last token then break the loop
if (jsonToken == null) {
break;
}
//If this is start of the object, then create
//Employee instance and add it to the result list
if (jsonToken.equals(JsonToken.START_OBJECT)) {
//Use the objectMapper to copy the current
// JSON object to Employee object
employee = objectMapper.readValue(jsonParser,
Employee.class);
//Add the newly copied instance to the list
employeeList.add(employee);
}
}
//Close the stream after the use to release the resources
if (inputStream != null) {
inputStream.close();
}
if (jsonParser != null) {
jsonParser.close();
}
Steps:
1) The JsonParser class reads the JSON content from the file input stream
2) The next step is to start parsing the JSON content read from the input source.
To learn all the possible token types returned by JsonParser in the Jackson framework, refer to
http://fasterxml.github.io/jackson-core/javadoc/2.5/com/fasterxml/jackson/core/JsonToken.html
Streaming APIs
Streaming APIs to generate JSON
/*Step 1: The following code snippet generates com.fasterxml.jackson.core.
JsonGenerator by using com.fasterxml.jackson.core.JsonFactory*/
OutputStream outputStream = new
FileOutputStream("emp-array.json");
JsonGenerator jsonGenerator = new
JsonFactory().createGenerator(outputStream,
JsonEncoding.UTF8);
/*Step 2: The next step is to build the JSON representation for the list of employees.
The writeStartArray() method writes the starting marker for the JSON array ([).
Now, write the marker for the object ({) by calling writeStartObject(). This is followed
by the name-value pairs for the object by calling an appropriate write method. To write the
end marker for the object (}), call writeEndObject(). Finally, to finish writing an array,
call writeEndArray()*/
jsonGenerator.writeStartArray();
List<Employee> employees = getEmployeesList();
for (Employee employee : employees) {
jsonGenerator.writeStartObject();
jsonGenerator.writeNumberField("employeeId",employee.getEmployeeId());
jsonGenerator.writeStringField("firstName", employee.getFirstName());
jsonGenerator.writeStringField("lastName", employee.getLastName());
jsonGenerator.writeEndObject();
}
//JsonGenerator class writes the JSON content to the
//specified OutputStream.
jsonGenerator.writeEndArray();
/*Step 3: Close the streams to release associated resources*/
jsonGenerator.close();
outputStream.close();
More details on Jackson are available at
https://github.com/FasterXML/Jackson
JAX-RS API
JAX-RS annotations
Java annotations provide the metadata for your Java class, which can be used during compilation, during deployment, or at runtime in order to perform designated tasks. The use of annotations allows us to create RESTful web services as easily as we develop a POJO class.
@Path
The @javax.ws.rs.Path annotation indicates the URI path to which a resource class or a class method will respond.
/* POJO class respond to a URI path template
containing the /departments path fragment */
import javax.ws.rs.Path;
@Path("departments")
public class DepartmentService {
//Rest of the code goes here
}
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
@Path("departments")
public class DepartmentService {
@GET
@Path("count")
@Produces("text/plain")
public Integer getTotalDepartments() {
return findTotalRecordCount();
}
//Rest of the code goes here
}
http://host:port/<context-root>/<application-path>
Variables in the URI path template
The @javax.ws.rs.Path annotation indicates the URI path to which a resource class or a class method will respond.
import javax.ws.rs.Path;
import javax.ws.rs.DELETE;
@Path("departments")
public class DepartmentService {
@DELETE
@Path("{id}")
public void removeDepartment(
@PathParam("id") short id) {
removeDepartmentEntity(id);
}
//Other methods removed for brevity
}
@DELETE
@Path("{name: [a-zA-Z][a-zA-Z_0-9]}")
public void removeDepartmentByName(@PathParam("name")
String deptName) {
//Method implementation goes here
}
The path URI looks like /departments/10
Restricting values for path variables with regular expressions
JAX-RS lets you use regular expressions in the URI path template for restricting the values set for the path variables at runtime by the client.
Annotations for specifying request-response
media types
@Produces
The @javax.ws.rs.Produces annotation is used for defining the Internet media type(s) that a REST resource class method can return to the client.
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("departments")
@Produces(MediaType.APPLICATION_JSON)
public class DepartmentService{
//Class implementation goes here...
}
• application/atom+xml
• application/json
• application/octet-stream
• application/svg+xml
• application/xhtml+xml
• application/xml
• text/html
• text/plain
• text/xml
@Consumes
The @javax.ws.rs.Consumes annotation defines the Internet media type(s) that the resource class methods can accept.
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.POST;
@POST
@Consumes(MediaType.APPLICATION_JSON)
public void createDepartment(Department entity) {
//Method implementation goes here…
}
• application/atom+xml
• application/json
• application/octet-stream
• application/svg+xml
• application/xhtml+xml
• application/xml
• text/html
• text/plain
• text/xml
• multipart/form-data
• application/x-www-form-urlencoded
Annotations for processing HTTP request methods
@GET
A RESTful system uses the HTTP GET method type for retrieving the resources referenced in the URI path.
//imports removed for brevity
@Path("departments")
public class DepartmentService {
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<Department> findAllDepartments() {
//Find all departments from the data store
List<Department> departments = findAllDepartmentsFromDB();
return departments;
}
//Other methods removed for brevity
}
The complete URI path may take the following URI pattern:
http://host:port/<context-root>/<application-path>/departments
@PUT
The HTTP PUT method is used for updating or creating the resource pointed by the URI.
@PUT
@Path("{id}")
@Consumes(MediaType.APPLICATION_JSON)
public void editDepartment(@PathParam("id") Short id,
Department department) {
//Updates department entity to data store
updateDepartmentEntity(id, department);
}
The payload present in the message body will be converted and copied to the department parameter by the framework
@POST
The HTTP POST method posts data to the server. Typically, this method type is used for creating a resource.
@POST
public void createDepartment(Department department) {
//Create department entity in data store
createDepartmentEntity(department);
}
@DELETE
The HTTP DELETE method deletes the resource pointed by the URI.
@DELETE
@Path("{id}")
public void removeDepartment(@PathParam("id") Short id) {
//remove department entity from data store
removeDepartmentEntity(id);
}
Annotations for accessing request parameters
@PathParam
The @javax.ws.rs.PathParam annotation injects (or binds) the value of the matching path parameter present in the URI path template into a class field, a resource class bean property (the getter method for accessing the attribute), or a method parameter.
//Other imports removed for brevity
javax.ws.rs.PathParam
@Path("departments")
public class DepartmentService {
@DELETE
@Path("{id}")
public void removeDepartment(@PathParam("id") Short deptId) {
removeDepartmentEntity(deptId);
}
//Other methods removed for brevity
}
The URI path template for this example looks like /departments/{id}
@Produces(MediaType.APPLICATION_JSON)
@Path("{country}/{city}")
public List<Department> findAllDepartments(
@PathParam("country") String countyCode,
@PathParam("city") String cityCode) {
//Find all departments from the data store for a country
//and city
List<Department> departments =
findAllMatchingDepartmentEntities(countyCode,
cityCode );
return departments;
}
The URI path template for this example looks like /departments/{country}/{city}
@QueryParam
The @javax.ws.rs.QueryParam annotation injects the value(s) of a HTTP query parameter into a class field, a resource class bean property (the getter method for accessing the attribute), or a method parameter.
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<Department>
findAllDepartmentsByName(@QueryParam("name") String deptName) {
List<Department> depts= findAllMatchingDepartmentEntities(deptName);
return depts;
}
The URI path template for this example looks like /departments?name=IT
@MatrixParam
The matrix parameters take the form of name-value pairs in the URI path, where each pair is preceded by semicolon (;).
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("matrix")
public List<Department> findAllDepartmentsByNameWithMatrix(
@MatrixParam("name") String deptName,
@MatrixParam("city") String locationCode) {
List<Department> depts=findAllDepartmentsFromDB(deptName,city);
return depts;
}
The URI path template for this example looks like /departments;name=IT;city=Bangalore
Comon practice for PathParam, QueryParam, and MatrixParam
PathParam
To drill down to the entity class hierarchy. For example, you may use the URI of the following form to identify an employee working in a specific department /departments/{dept}/employees/{id}
QueryParam
Can be used for specifying attributes to locate the instance of a class. For example, you may use URI with QueryParam to identify employees who have joined on January 1, 2015, which may look like /employees?doj=2015-01-01
MatrixParam
Is not used frequently. This is useful when you need to make a complex REST style query to multiple levels of resources and subresources. MatrixParam is applicable to a particular path element, while the query parameter is applicable to the entire request.
@HeaderParam
The @javax.ws.rs.HeaderParam annotation injects the header values present in the request into a class field, a resource class bean property (the getter method for accessing the attribute), or a method parameter
@POST
public void createDepartment(
@HeaderParam("Referer") String referer, Department entity) {
logSource(referer);
createDepartmentInDB(department);
}
You can use custom HTTP headers to pass some application-specific data to the server, try using standard headers whenever possible.
@CookieParam
The @javax.ws.rs.CookieParam annotation injects the matching cookie parameters
present in the HTTP headers into a class field, a resource class bean property (the
getter method for accessing the attribute), or a method parameter.
@GET
@Path("cook")
@Produces(MediaType.APPLICATION_JSON)
public Department getDefaultDepartment(
@CookieParam("Default-Dept") short departmentId) {
Department dept=findDepartmentById(departmentId);
return dept;
}
You can use custom HTTP headers to pass some application-specific data to the server, try using standard headers whenever possible.
@FormParam
Injects the matching HTML form parameters present in the request body into a class field, a resource class bean property (the getter method for accessing the attribute), or a method parameter.
<!DOCTYPE html>
<html>
<head>
<title>Create Department</title>
</head>
<body>
<form method="POST" action="/resources/departments">
Department Id:
<input type="text" name="departmentId">
<br>
Department Name:
<input type="text" name="departmentName">
<br>
<input type="submit" value="Add Department" />
</form>
</body>
</html>
The request body carrying the form elements must have the content type specified as application/x-www-form-urlencoded.
@Path("departments")
public class DepartmentService {
@POST
//Specifies content type as
//"application/x-www-form-urlencoded"
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void createDepartment(
@FormParam("departmentId") short departmentId,
@FormParam("departmentName") String departmentName) {
createDepartmentEntity(departmentId, departmentName);
}
}
@DefaultValue
The @javax.ws.rs.DefaultValue annotation specifies a default value for the request parameters accessed using one of the following annotations: PathParam, QueryParam, MatrixParam, CookieParam, FormParam, or HeaderParam. The default value is used if no matching parameter value is found for the variables annotated using one of the preceding annotations.
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<Department> findAllDepartmentsInRange(
@DefaultValue("0") @QueryParam("from") Integer from,
@DefaultValue("100") @QueryParam("to") Integer to){
findAllDepartmentEntitiesInRange(from, to);
}
@BeanParam
The @javax.ws.rs.BeanParam annotation allows you to inject all matching request parameters into a single bean object. The @BeanParam annotation can be set on a class field, a resource class bean property (the getter method for accessing the attribute), or a method parameter. @PathParam, @QueryParam, @MatrixParam, @HeaderParam, @CookieParam, or @FormParam
public class DepartmentBean {
@FormParam("departmentId")
private short departmentId;
@FormParam("departmentName")
private String departmentName;
//getter and setter for the above fields
//are not shown here to save space
}
The DepartmentBean class that we use for this example is as follows:
@POST
public void createDepartment(@BeanParam DepartmentBean deptBean)
{
createDepartmentEntity(deptBean.getDepartmentId(),
deptBean.getDepartmentName());
}
public void createDepartment(
@FormParam("departmentId") short departmentId,
@FormParam("departmentName") String departmentName)
Instead of this:
Returning additional metadata with responses
JAX-RS allows you to return additional metadata via the javax.ws.rs.core. Response class that wraps the entity and additional metadata such as the HTTP headers, HTTP cookie, and status code.
//Other imports removed for brevity
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response findAllDepartmentsByName( @QueryParam("name") String deptName ) {
List<Department> depts= findAllMatchingDepartmentEntities(deptName);
//Sets cache control directive to the response
CacheControl cacheControl = new CacheControl();
//Cache the result for a day
cacheControl.setMaxAge(86400);
return Response.ok().cacheControl(cacheControl).entity(depts).build();
}
Understanding data binding rules
in JAX-RS
Mapping the path variable with Java types
JAX-RS allows you to use @QueryParam and @PathParam on the following Java types
• All primitive types such as short, int, float, double, and Boolean, except char.
• All the wrapper classes of primitive types, such as short, integer, BigDecimal, and Boolean, except char.
• All classes with a constructor that accepts a single string type argument.In this case, you can define your own class with a single string type constructor and use it as a method parameter or member variable with an appropriate annotation for reading the parameter value.
• Any class with the static method named valueOf(String) that accepts a single string argument.
• If the parameters contain more than one value for the same name, you can have java.util.List<T>, java.util.Set<T>, or java.util. SortedSet<T> as the Java variable type at the receiving end, where T represents the types that satisfy the first two criteria that we defined.
Mapping the request and response entity
body with Java types
JAX-RS offers the default content handlers (entity providers) for all common data types. Here is a list of the Java types supported by JAX-RS by default:
• JAX-RS supports mapping between the following Java data types and request-response entity bodies for all media forms: byte[], java.lang. String, java.io.InputStream, java.io.Reader, java.io.File, javax. activation.DataSource, and javax.xml.transform.Source
• JAX-RS supports the javax.ws.rs.core.MultivaluedMap<K,V> type for reading or writing the form content, whose media type is application/xwww-form-urlencoded
• JAX-RS supports the javax.xml.bind.JAXBElement type for reading or writing contents represented using the XML media types (text/xml,application/xml, and application/*+xml)
• JAX-RS supports the java.lang.Boolean, java.lang.Character, and java.lang.Number types for reading and writing the Boolean strings (true or false), characters, and numerical content presented in the text/plain media type.
Using JAXB to manage the mapping of the request and response entity body to Java objects
The default entity provider used by JAX-RS runtime makes use of JAXB annotation to map Java objects to XML or JSON representations.
@javax.xml.bind.annotation.XmlRootElement: When a top-level class is annotated with the @XmlRootElement annotation, the JAX-RS runtime takes care of the serialization of all its instances at runtime.
@javax.xml.bind.annotation.XmlAccessorType: This annotation controls whether the fields or JavaBean properties are serialized by default. It takes the following values:
°XmlAccessType.FIELD: Every non-static, non-transient field will be copied in the XML or JSON representation
°XmlAccessType.NONE: No fields are copied
°XmlAccessType.PROPERTY: Every getter/setter pair will be copied in the XML or JSON representation
°XmlAccessType.PUBLIC_MEMBER: Every public field and the public getter/setter pair will be copied in the XML or JSON representation
@javax.xml.bind.XmlElement: This value maps a JavaBean property to an XML or JSON element derived from the property name
@javax.xml.bind.XmlTransient: This value prevents the mapping of a JavaBean property/type to JSON
Using JAXB to manage the mapping of the request and response entity body to Java objects
The JAX-RS runtime deploys entity providers that implement javax.ws.rs.ext.MessageBodyWriter to serialize Java objects into an appropriate output stream representation such as JSON or XML. The MessageBodyWriter implementation scans through the JAXB annotations defined on the Department class and converts values to the JSON data as appropriate.
//Other imports removed for brevity
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
@XmlRootElement(name="department")
@XmlAccessorType(XmlAccessType.FIELD)
public class Department implements Serializable {
@XmlElement(name="departmentId")
private Short id;
private String departmentName;
@XmlTransient
public List<Employee> employees;
//Rest of the code removed for brevity
}
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public Department find(@PathParam("id") Short id) {
return findDepartmentEntity(id);
}
//This is the JSON output
{"departmentId":30,
"departmentName":"HR"}
//List<Employee> employees field that you
//see in the Department class
//is not present in the JSON output data
//because this field is marked as @XmlTransient
RESTful web service
with JAX-RS
Setting up the environment
• Java SE Development Kit 8 or newer
• NetBeans IDE 8.0.2 (with Java EE bundle) or newer
• Glassfish Server 4.1 or newer (https://glassfish.java.net/)
• Maven 3.2.3 or newer
• Oracle Database Express Edition 11g Release 2 or newer with HR sample database schema
• Oracle Database JDBC Driver (ojdbc7.jar or newer)
Building a simple RESTful web service
application using NetBeans IDE
1. Launch NetBeans IDE.
2. In the main toolbar, navigate to File | New Project.
3. On the New Project dialog screen, navigate to Maven | Web Application for building the RESTful web service. Proceed to the next screen by clicking on the Next button.
4. In the Name and Location screen, enter Project Name, Project Location (for storing the source), Group Id, Version (for the Maven project), and Package (for the Java source files) as follows:
° Project Name: rest-chapter3-service
° Group Id: com.packtpub
° Package: com.packtpub.rest.ch3.service
5. On the Settings screen, select GlassFish Server that you have installed along with NetBeans IDE as Server for running your JAX-RS application, and then click on Java EE 7 Web as the Java EE version for the application that you build.
Building a simple RESTful web service
application using NetBeans IDE
6. The server list on this screen may appear empty if you have not configured any server for the IDE yet. To add a new server reference, perform the following steps:
1. Click on the Add button. In the Add Server Instance wizard, choose GlassFish as the server and click on Next to continue the wizard.
2. Set Server Location to the folder where you installed GlassFish. Select Local Domain and click on Next to continue the wizard.
3. On the Domain Name screen, enter domain1 in the Domain field (which is the default one) and localhost in the Host field. Click on Finish to complete the server creation.
4. Now, IDE will take you back to the Setting screen once again where you can choose GlassFish (that you have added in the previous step) as the server and Java EE 7 Web as the Java EE version.
7. You can now click on the Finish button to finish the project configuration wizard.
8. The next step is to build a simple RESTful web service implementation by using a POJO class to get a feel of the JAX-RS APIs. To build a POJO class, you can right-click on the project and navigate to New | Java Class in the menu. In the New Java Class editor, enter
DepartmentService in the Class Name field and enter com.packtpub.rest.ch3.service in the Package field. This class will contain the service implementation for this example.
Building a simple RESTful web service
application using NetBeans IDE
9. We will add @Path("departments") to this class so that DepartmentService becomes a REST resource class and responds to the REST API calls with the URI path fragment \departments. Let's add a simple helloWorld() method to this class and add @Path("hello") to this method. Add the @GET annotation to designate this method to respond to the HTTP GET methods.
10. To configure resources, add a REST configurations class, which extends javax.ws.rs.core.Application. This class defines the components of a JAX-RS application and supplies additional metadata, if any.
package com.packtpub.rest.ch3.service;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("departments")
public class DepartmentService{
@GET
@Path("hello")
@Produces(MediaType.APPLICATION_JSON)
public String helloWorld(){
return "Hello world";
}
}
package com.packtpub.rest.ch3.jaxrs.service;
import java.util.Set;
import javax.ws.rs.core.Application;
@javax.ws.rs.ApplicationPath("webresources")
public class RestAppConfig extends Application {
// Get a set of root resource and provider classes.
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources =
new java.util.HashSet<>();
resources.add(com.packtpub.rest.ch3.service.DepartmentService.class);
return resources;
}
}
9)
10)
Alternatively, you can define the application path in web.xml. However, to keep things simple, we will not use web.xml for configuring resources in this example.
Building a simple RESTful web service
application using NetBeans IDE
11. To deploy and run the RESTful web service application, you can right-click on the rest-chapter3-service project and click on Run. This will build and deploy the application to the GlassFish server integrated with NetBeans IDE.
12. To test the desired REST API, right-click on the appropriate HTTP methods, as shown in the following screenshot, and select Test Resource Uri. This action will open up the default browser with the response content returned by the REST call. The URI for accessing the helloWorld RESTful web API will look like http://localhost:8080/rest-chapter3-service/webresources/departments/hello
Thanks for your
attention
References
Restful Java Web Services(1-92). 2nd ed. Birmingham: Packt Publishing Ltd., 2017. Ebook.
http://www.flaticon.com/
Restful Java Web Services
By Irving Norehem Llamas Covarrubias
Restful Java Web Services
- 465