10.09.2012
REST-Schnittstelle für JEE6 - Java Enterprise Edition 6
In diesem Artikel wird erklärt, wie man mit ein paar Zeilen Quellcode ein Enterprise Java Bean (EJBs) um eine REST-Schnittstelle erweitert. Die Schnittstelle wird GET
, POST
und PUT
unterstützen.
Es wird im Folgenden vorausgesetzt, dass das Beispiel aus JEE6-Tutorial durchgearbeitet wurde und die Klassen bekannt sind.
In dem Artikel soll eine EJB (Enterprise Java Bean) so erweitert werden, dass sie über eine REST-Schnittstelle angesprochen werden kann. Der Einfachheit halber verwenden wir in dem Beispiel die Klasse UrlManagerBean
aus dem JEE6-Tutorial und erweitern sie um die Annotation @Path("/urlmanager")
. Damit wird der Pfad der URL angegeben unter der der Service später zu erreichen ist.
package org.hameister.urlmanager; import java.util.ArrayList; import java.util.List; import javax.ejb.Stateless; import javax.inject.Named; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; /** * * @author Hameister */ //@Interceptors(UrlManagerInterceptor.class) @Stateless @Named @Path("/urlmanager") public class UrlManagerBean { @PersistenceContext EntityManager em; public void addUrl(UrlManagerEntity entity) { System.out.println("Added"); em.persist(entity); } public List<String> getUrls() { List<String> urls = new ArrayList<String>(); Query query = em.createQuery("SELECT url FROM UrlManagerEntity url"); List<UrlManagerEntity> resultList = query.getResultList(); for(UrlManagerEntity entity : resultList) { urls.add(entity.getUrl()); } return urls; }
Als erstes ergänzen wir eine Funktion, die die zuletzt hinzugefügte URL bestimmt und einen String
zurückliefert. Dazu ergänzen wird die Annotation @GET
, die angibt, dass es sich um ein HTTP-GET handelt. Bei @Path("lasturl")
handelt es sich um einen weiteren Unterpfad für den Service. Der Wert @Produces("text/plain")
legt den Rückgabetyp des REST-Services fest.
@GET @Path("lasturl") @Produces("text/plain") public String lastUrl() { Query query = em.createQuery("SELECT url FROM UrlManagerEntity url"); List<UrlManagerEntity> resultList = query.getResultList(); return resultList.get(resultList.size()-1).getUrl(); }
Es ist anzumerken, dass die Überprüfung, ob die resultList
leer oder null
ist, der Übersichtlichkeit wegen, weggelassen wurde!
In dem Beispiel eben wurde ein einfacher String
zurückgeliefert. Allerdings ist es auch möglich, komplexere Datenstrukturen als Rückgabewerte anzugeben. In dem folgenden Beispiel wird wieder die zuletzt hinzugefügte URL bestimmt, aber diesmal wird direkt das Objekt UrlManagerEntity
an den Aufrufenden zurückgegeben. Als Rückgabetyp wurde mit der Annotation @Produces
gesagt, dass es sich um das JSON-Format handelt.
@GET @Path("lasturlmanager") @Produces("application/json") public UrlManagerEntity lastUrlManager() { Query query = em.createQuery("SELECT url FROM UrlManagerEntity url"); List<UrlManagerEntity> resultList = query.getResultList(); return resultList.get(resultList.size()-1); }
Allerdings ist es auch möglich eine Liste mit Objekten vom Typ UrlManagerEntity
zurückzuliefern. Dazu werden diesmal für @Produces
die Typen {"application/xml", "application/json"}
eingetragen. Das bedeutet, dass die Methode sowohl XML als auch JSON als Ergebnis liefern kann.
@GET @Path("/findAll") @Produces({"application/xml", "application/json"}) public List<UrlManagerEntity> findAll() { Query query = em.createQuery("SELECT url FROM UrlManagerEntity url"); List<UrlManagerEntity> resultList = query.getResultList(); return resultList; }
Als letzte Methode soll noch die Möglichkeit angeboten werden, dass neue URLs über die REST-Schnittstelle in die Datenbank geschrieben werden können. Dazu definieren wir eine @POST
-Methode, die JSON als Eingabetyp versteht und als Objekt ein entity
vom Typ UrlManagerEntity
übergeben bekommt.
@POST @Path("/saveUrl") @Consumes("application/json") public void saveUrl(UrlManagerEntity entity) { em.persist(entity); }
Damit die problemlose Serialisierung von UrlManagerEntity
funktioniert, ist es notwendig Änderungen an der Klasse UrlManagerEntity
vorzunehmen. Es werden die beiden Annotationen @XmlRootElement
und @XmlAccessorType(XmlAccessType.FIELD)
ergänzt.
Bei meinen Tests war es außerdem erforderlich, dass ein default-Konstruktor mit der Sichtbarkeit protected
vorhanden war, damit die Testanwendung Test RESTful Web Services die Rückgabewerte der REST-Methoden richtig anzeigt. Ich bin allerdings der Meinung, dass das normalerweise nicht notwendig ist und nur auf ein Problem mit Jersey im Glassfish zurückzuführen ist.
package org.hameister.urlmanager; import java.io.Serializable; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; /** * * @author Hameister */ @Entity @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class UrlManagerEntity implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String url; UrlManagerEntity() { } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } ... }
Zum Testen des REST-Service mit NetBeans muss als erstes die Anwendung auf dem Glassfish deployt werden. Beim ersten Deployment fragt NetBeans wie die Anwendung registriert werden soll.
Da es sich um eine JEE6-Anwendung handelt, sollte der erste Punkt ausgewählt werden. Dadurch wird eine Wrapper-Klasse ApplicationContext.java
generiert.
Anschliessend selektiert man das Projekt und wählt im Kontextmenü den Menüpunkt Test RESTful Web Services... aus. In dem Dialog ist der Punkt Locally Generated Test Client (suitable for Internet Explorer, Firefox) selektiert.
Daraufhin öffnet sich der Standard-Browser mit der Seite Test RESTful Web Services. Dabei handelt es sich um eine Anwendung zum Testen der REST Services.
Auf der Seite sind alle deployten WebServices zu sehen, die nun einfach getestet werden können.
Beispielsweise kann eine neue URL in die Datenbank eingefügt werden indem man den Service saveURL
mit dem Content {"url":"http://www.hameister.org"}
aufruft. Als Format wird dabei JSON verwendet:
Es ist natürlich auch möglich den WebService von anderen Anwendungen aus anzusprechen. Beispielsweise kann auch Curl verwendet werden. Einfache GET
-Anfragen können auch über einen Browser abgesetzt werden.
Weitere Informationen
Die Java API for RESTful Web Services (JAX-RS) 1.1 gehört zu JSR-311. Hier findet man das PDF mit der Spezifikation dazu.
- JEE6-Tutorial
- EJB-Tutorial
- TimerService
- Interceptors
- Bean-Validation
- Remote Zugriff auf EJBs mit einem Standalone-Java-Client
- Unit-Tests für EJBs mit einem Embeddable-Container