Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (7.32 MB, 392 trang )
return id;
}
public void setId(int id) {
this.id = id;
}
@XmlElement(name="first-name")
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
@XmlElement(name="last-name")
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@XmlElement
public String getStreet() {
return street;
}
...
}
The JAXB annotations provide a mapping between the Customer class and XML.
You don’t need to write a lot of code to implement the JAX-RS service because JAX-RS
already knows how to handle JAXB annotated classes:
src/main/java/com/restfully/shop/services/CustomerResource.java
@Path("/customers")
public class CustomerResource {
private Map
new ConcurrentHashMap
private AtomicInteger idCounter = new AtomicInteger();
public CustomerResource() {
}
@POST
@Consumes("application/xml")
public Response createCustomer(Customer customer) {
customer.setId(idCounter.incrementAndGet());
customerDB.put(customer.getId(), customer);
280
|
Chapter 21: Examples for Chapter 6
www.it-ebooks.info
System.out.println("Created customer " + customer.getId());
return Response.created(URI.create("/customers/" +
customer.getId())).build();
}
@GET
@Path("{id}")
@Produces("application/xml")
public Customer getCustomer(@PathParam("id") int id) {
Customer customer = customerDB.get(id);
if (customer == null) {
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
return customer;
}
@PUT
@Path("{id}")
@Consumes("application/xml")
public void updateCustomer(@PathParam("id") int id,
Customer update) {
Customer current = customerDB.get(id);
if (current == null)
throw new WebApplicationException(Response.Status.NOT_FOUND);
current.setFirstName(update.getFirstName());
current.setLastName(update.getLastName());
current.setStreet(update.getStreet());
current.setState(update.getState());
current.setZip(update.getZip());
current.setCountry(update.getCountry());
}
}
If you compare this with the CustomerResource class in ex03_1, you’ll see that the code
in this example is much more compact. There is no handcoded marshalling code, and
our methods are dealing with Customer objects directly instead of raw strings.
The Client Code
The client code can also now take advantage of automatic JAXB marshalling. All JAXRS 2.0 client implementations must support JAXB as a mechanism to transmit XML on
the client side. Let’s take a look at how the client code has changed from ex03_1:
@Test
public void testCustomerResource() throws Exception
{
System.out.println("*** Create a new Customer ***");
Customer newCustomer = new Customer();
newCustomer.setFirstName("Bill");
Example ex06_1: Using JAXB
www.it-ebooks.info
|
281
newCustomer.setLastName("Burke");
newCustomer.setStreet("256 Clarendon Street");
newCustomer.setCity("Boston");
newCustomer.setState("MA");
newCustomer.setZip("02115");
newCustomer.setCountry("USA");
We start off by allocating and initializing a Customer object with the values of the new
customer we want to create.
Response response =
client.target("http://localhost:8080/services/customers")
.request().post(Entity.xml(newCustomer));
if (response.getStatus() != 201)
throw new RuntimeException("Failed to create");
The code for posting the new customer looks exactly the same as ex03_1 except that
instead of initializing a javax.ws.rs.client.Entity with an XML string, we are using
the Customer object. The JAX-RS client will automatically marshal this object into an
XML string and send it across the wire.
Changes to pom.xml
JBoss RESTEasy is broken up into a bunch of smaller JARs so that you can pick and
choose which features of RESTEasy to use. Because of this, the core RESTEasy JAR file
does not have the JAXB content handlers. Therefore, we need to add a new dependency
to our pom.xml file:
Adding this dependency will add the JAXB provider to your project. It will also pull in
any third-party dependency RESTEasy needs to process XML. If you are deploying on
a Java EE application server like Wildfly or JBoss, you will not need this dependency;
JAXB support is preinstalled.
Build and Run the Example Program
Perform the following steps:
1. Open a command prompt or shell terminal and change to the ex06_1 directory of
the workbook example code.
2. Make sure your PATH is set up to include both the JDK and Maven, as described
in Chapter 17.
282
| Chapter 21: Examples for Chapter 6
www.it-ebooks.info
3. Perform the build and run the example by typing maven install.
Example ex06_2: Creating a Content Handler
For this example, we’re going to create something entirely new. The Chapter 6 example
of a content handler is a reimplementation of JAXB support. It is suitable for that chapter
because it illustrates both the writing of a MessageBodyReader and a MessageBodyWrit
er and demonstrates how the ContextResolver is used. For ex06_2, though, we’re going
to keep things simple.
In ex06_2, we’re going to rewrite ex06_1 to exchange Java objects between the client and
server instead of XML. Java objects, you ask? Isn’t this REST? Well, there’s no reason a
Java object can’t be a valid representation of a resource! If you’re exchanging Java objects,
you can still realize a lot of the advantages of REST and HTTP. You still can do content
negotiation (described in Chapter 9) and HTTP caching (described in Chapter 11).
The Content Handler Code
For our Java object content handler, we’re going to write one class that is both a
MessageBodyReader and a MessageBodyWriter:
src/main/java/com/restfully/shop/services/JavaMarshaller.java
@Provider
@Produces("application/example-java")
@Consumes("application/x-java-serialized-object")
public class JavaMarshaller
implements MessageBodyReader, MessageBodyWriter
{
The JavaMarshaller class is annotated with @Provider, @Produces, and @Consumes, as
required by the specification. The media type used by the example to represent a Java
object is application/example-java:1
public boolean isReadable(Class type, Type genericType,
Annotation[] annotations, MediaType mediaType)
{
return Serializable.class.isAssignableFrom(type);
}
public boolean isWriteable(Class type, Type genericType,
Annotation[] annotations, MediaType mediaType)
{
1. The media type application/x-java-serialized-object should actually be used, but as of the second
revision of this book, RESTEasy now has this type built in.
Example ex06_2: Creating a Content Handler
www.it-ebooks.info
|
283
return Serializable.class.isAssignableFrom(type);
}
For the isReadable() and isWriteable() methods, we just check to see if our Java type
implements the java.io.Serializable interface:
public Object readFrom(Class type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap httpHeaders,
InputStream is)
throws IOException, WebApplicationException
{
ObjectInputStream ois = new ObjectInputStream(is);
try
{
return ois.readObject();
}
catch (ClassNotFoundException e)
{
throw new RuntimeException(e);
}
}
The readFrom() method uses basic Java serialization to read a Java object from the
HTTP input stream:
public long getSize(Object o, Class type,
Type genericType, Annotation[] annotations,
MediaType mediaType)
{
return −1;
}
The getSize() method returns –1. It is impossible to figure out the exact length of our
marshalled Java object without serializing it into a byte buffer and counting the number
of bytes. We’re better off letting the servlet container figure this out for us. The get
Size() method has actually been deprecated in JAX-RS 2.0.
public void writeTo(Object o, Class type,
Type genericType, Annotation[] annotations,
MediaType mediaType,
MultivaluedMap httpHeaders, OutputStream os)
throws IOException, WebApplicationException
{
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(o);
}
Like the readFrom() method, basic Java serialization is used to marshal our Java object
into the HTTP response body.
284
|
Chapter 21: Examples for Chapter 6
www.it-ebooks.info
The Resource Class
The CustomerResource class doesn’t change much from ex06_2:
src/main/java/com/restfully/shop/services/CustomerResource.java
@Path("/customers")
public class CustomerResource
{
...
@POST
@Consumes("application/example-java")
public Response createCustomer(Customer customer)
{
customer.setId(idCounter.incrementAndGet());
customerDB.put(customer.getId(), customer);
System.out.println("Created customer " + customer.getId());
return Response.created(URI.create("/customers/"
+ customer.getId())).build();
}
...
}
The code is actually exactly the same as that used in ex06_1, except that the @Pro
duces and @Consumes annotations use the application/example-java media type.
The Application Class
The ShoppingApplication class needs to change a tiny bit from the previous examples:
src/main/java/com/restfully/shop/services/ShoppingApplication.java
public class ShoppingApplication extends Application {
private Set