RESTful web-services in Java using JAX-RS - Part 1: Getting up and running
After having spent some time working with Suns JAX-RS implementation Jersey and integrating RESTful-services in a few products i work on, i thought it might be a good idea to share my experiences.
So i decided to write a few blog-posts. I am not sure yet how many parts there will be, my current plan are 3. In this first part i want to talk about the "trivial" things. It took me some time to gather all the information i needed, especially the Maven artifacts to include were not obvious to me.
Maven: Getting Jersey into your project
In this post i will assume, that you are working on a web-project and use Maven as build-tool. I run most of my apps with an embedded Tomcat, but you can just as well deploy the resulting war to any other container. Further i will explain how to use Suns Jersey, so if you have reasons to use a different JAX-RS-implementation, this part will not apply to you. (If you think these reasons might apply to others as well, please let me know, i am always happy to learn about alternatives.)
Last time i checked, the current versions of Jersey were not available on Mavens central repository. To get them add the following repository to your pom.xml (unless you already have for other dependencies):
<repositories>
<repository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net Repository for Maven</name>
<url>http://download.java.net/maven/2/</url>
</repository>
</repositories>Now add the following artifacts:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.0.3.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.1.12</version>
<scope>compile</scope>
</dependency>This should pull in everything else to get a basic web-service up and running.
If you want to put some classes for your web-service into an external pojo, just add the following artifacts to its pom.xml:
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>Integration work: How to get Jersey running
First we need to map some requests to Jersey, this works by registering a servlet in your web.xml. Just add this:
<servlet>
<servlet-name>Jersey Servlet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>my.package.api</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Servlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>Replace my.package.api with the real package you intend to use for your resource-classes.
We're mostly done with the implementation specific parts. The next steps involve only JAX-RS things, which lets you take your webservice-classes to any JAX-RS-implementation you like.
Hello World: Your first REST resource
Just really quick: in RESTful web-services everything is modeled as a resource, so basically you create operations for CRUD (create, read, update, delete). For different operations, different HTTP-methods are used, mainly GET, POST and DELETE. You might also use PUT sometimes. Important: it should never matter wether the same GET-request is sent multiple times.
Lets create a first, really basic resource-class:
@Path("/notes") @Produces({"application/xml"}) public class NotesHandler { @GET public String list() { return "Hello World, I still need some work to be useful!"; } }
After deploying this to the container of your choice, you can open /api/notes in your web-browser. This should produce an xml-syntax-error, since only "Hello World, I still need some work to be useful!" is returned, which is obviously not valid xml.
So lets move on to create a class to wrap our result. We'll use JAXB-annotations to have this easily marshalled to xml:
@XmlRootElement(name="notes") public class NotesList { private String result; public NotesList() { } public NotesList(String result) { this.result = result; } public String getResult() { return result; } public void setResult(String result) { this.result = result; } }
Now, also modify your handler-class like this:
@GET
public NotesList list() {
return new NotesList("Hello World, I still need some work to be useful!");
}We now get valid xml, but this is still really useless. Lets add some logic to it:
@Path("/notes") @Produces({"application/xml"}) public class NotesHandler { /** * This is really, really wrong. Just so that we can do some playing around * without having to setup a database. */ private static SortedMap<Long, Note> notes = new TreeMap<Long, Note>(); static { add("Hello World, I still need some work to be useful!"); } @GET public NotesList list() { NotesList result = new NotesList(); result.getNotes().addAll(notes.values()); return result; } private static Note add(String text) { Note note = new Note(notes.isEmpty() ? 1 : notes.lastKey(), text); notes.put(note.getId(), note); return note; } } @XmlRootElement(name="notes") public class NotesList { @XmlElement(name="note") private List<Note> notes = new ArrayList<Note>(); public NotesList() { } @XmlTransient public List<Note> getNotes() { return notes; } public void setNotes(List<Note> notes) { this.notes = notes; } } @XmlRootElement(name="note") @XmlType public class Note { private Long id; private String text; public Note() { } public Note(Long id, String text) { this.id = id; this.text = text; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getText() { return text; } public void setText(String text) { this.text = text; } }
Enough with that GET, lets go POST something
Wouldnt it be great, if we could actually create notes, too? In RESTful web-services this is done with POST instead of GET, so we'll change the add method to handle POSTs:
@POST
@Path("/new")
@Consumes("text/plain")
public Note add(String text) {
Note note = new Note(notes.isEmpty() ? 1 : notes.lastKey(), text);
notes.put(note.getId(), note);
return note;
}Also, remember to remove the static-block, that we added for testing.
You can now send a POST-request to /api/notes/new with the note as body to add a new note. I use the Firefox-extension Poster for this.
Okay... I think i'll just end this right here! I was going to write a little more, but this is getting really long as it is right now, so i'll just move the next steps to the next part!
I hope this is helpful for somebody to get started with JAX-RS.
- Awesome and legendary online pokertimer
- New releases for AuthenticRoast and ViewNControl
- New release of AuthenticRoast - Moved to Google code
- ViewNControl: VNC connections with pure HTML / JavaScript
- Make that mouse-pointer stay out of invisible areas
- RESTful web-services in Java using JAX-RS - Part 1: Getting up and running
- SumtnSumtn goes public :-)
- Problems with f:param inside h:outputLink
- Tomcat and UTF-8
- Multihead in KDE 4.2.2
Aike J Sommer