I have implemented Atom support which will be available with the next release of RESTEasy.
Although the Atom format is used primarily for the syndication of blogs and news, many are starting to use this format as the envelope for Web Services, for example, distributed notifications, job queues, or simply a nice format for sending or receiving data in bulk from a service.
RESTEasy has defined a simple object model in Java to represent Atom and uses JAXB to marshal and unmarshal it. The main classes are in the org.jboss.resteasy.plugins.providers.atom package and are Feed, Entry, Content, and Link. If you look at the source, you’d see that these are annotated with JAXB annotations. The distribution contains the javadocs for this project and are a must to learn the model. Here is a simple example of sending an atom feed using the Resteasy API.
import org.jboss.resteasy.plugins.providers.atom.Content; import org.jboss.resteasy.plugins.providers.atom.Feed; import org.jboss.resteasy.plugins.providers.atom.Link; import org.jboss.resteasy.plugins.providers.atom.Person; @Path("atom") public class MyAtomService { @GET @Path("feed") @Produces("application/atom+xml") public Feed getFeed() { Feed feed = new Feed(); feed.setId(new URI("http://example.com/42")); feed.setTitle("My Feed"); feed.setUpdated(new Date()); Link link = new Link(); link.setHref(new URI("http://localhost")); link.setRel("edit"); feed.getLinks().add(link); feed.getAuthors().add(new Person("Bill Burke")); Entry entry = new Entry(); entry.setTitle("Hello World"); Content content = new Content(); content.setType(MediaType.TEXT_HTML_TYPE); content.setText("Nothing much"); feed.getEntries().add(content); return feed; } }
Because Resteasy’s atom provider is JAXB based, you are not limited to sending atom objects using XML. You can automatically re-use all the other JAXB providers that Resteasy has like JSON and fastinfoset. All you have to do is have “atom+” in front of the main subtype. i.e. @Produces(“application/atom+json”) or @Consumes(“application/atom+fastinfoset”)
The org.jboss.resteasy.plugins.providers.atom.Content class allows you to unmarshal and marshal JAXB annotated objects that are the body of the content. Here’s an example of sending an Entry with a Customer object attached as the body of the entry’s content.
@XmlRootElement(namespace = "http://jboss.org/Customer") @XmlAccessorType(XmlAccessType.FIELD) public class Customer { @XmlElement private String name; public Customer() { } public Customer(String name) { this.name = name; } public String getName() { return name; } } @Path("atom") public static class AtomServer { @GET @Path("entry") @Produces("application/atom+xml") public Entry getEntry() { Entry entry = new Entry(); entry.setTitle("Hello World"); Content content = new Content(); content.setJAXBObject(new Customer("bill")); entry.setContent(content); return entry; } }
The Content.setJAXBObject() method is used to tell the content object you are sending back a Java JAXB object and want it marshalled appropriately. If you are using a different base format other than XML, i.e. “application/atom+json”, this attached JAXB object will be marshalled into that same format.
If you have an atom document as your input, you can also extract JAXB objects from Content using the Content.getJAXBObject(Class clazz) method. Here is an example of an input atom document and extracting a Customer object from the content.
@Path("atom") public class AtomServer { @PUT @Path("entry") @Produces("application/atom+xml") public void putCustomer(Entry entry) { Content content = entry.getContent(); Customer cust = content.getJAXBObject(Customer.class); } }
Nov 11, 2008 @ 22:14:56
As before – because the signup for Jira submission of bugs for RESTeasy is onerous… I’ve come across a somewhat odd corner case in dealing with parameters on some fairly simple methods (really just mucking around with Hello World style code to get my feet wet with the various implementations of JAX-RS).
package rest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
@Path("/hello")
public class Hello {
@GET
@Produces("text/plain")
public String sayHelloPlain() {
return new String("Hello there.");
}
@GET
@Produces("text/html")
public String querySayHelloHTML(@QueryParam("name") String name) {
if (name == null || name.trim().length() == 0) return sayHelloHTML();
return new String("HelloHello " + name + ".");
}
@GET
@Path("/name/{name}")
@Produces("text/html")
public String pathSayHelloHTML(@PathParam("name") String name) {
if (name == null || name.trim().length() == 0) return sayHelloHTML();
return new String("HelloHello " + name + ".");
}
public String sayHelloHTML() {
return new String("HelloHello there.");
}
}
Pretty straight forward – two “GET”able resources to produced a customized “Hello” type message.
http://localhost:8080/RestZen/rest/hello
Produces the expected: Hello there. As does:
http://localhost:8080/RestZen/rest/hello?name=++++++
Whereas the following:
http://localhost:8080/RestZen/rest/hello?name=Porter
Produces: Hello Porter.
http://localhost:8080/RestZen/rest/hello/name/
Produces a 405 error – which I’m guessing is correct (no parameter supplied). However, the following URL produces a stack trace:
http://localhost:8080/RestZen/rest/hello/name/+++
With the following error:
java.lang.StringIndexOutOfBoundsException: String index out of range: -1
java.lang.String.substring(String.java:1938)
org.jboss.resteasy.specimpl.UriInfoImpl.(UriInfoImpl.java:95)
org.jboss.resteasy.plugins.server.servlet.ServletUtil.extractUriInfo(ServletUtil.java:62)
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:72)
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:66)
javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
Whereas the following URL does not:
http://localhost:8080/RestZen/rest/hello/name/%20%20%20
Producing a simple “Hello There.” instead. The + and %20 are interchangeable as far as URLs go – although Firefox does mangle the location bar by replacing the %20 with a normal space – yet if I type that in and submit it – I get a 405 – since it strips the trailing space prior to sending the URL. Anyhow – just struck me as odd that things blew up so badly on a ‘+’ (e.g. URL encoded space) as a character.
Nov 24, 2008 @ 18:27:36
Hi Bill, I’m trying to use resteasy and I need to put in the package-info.java two adapters. This is possible? Thanks!
Nov 24, 2008 @ 18:43:16
Diego, I’m not understanding you. adapters for what?
Also, please post to our mailling list instead:
https://lists.sourceforge.net/lists/listinfo/resteasy-developers