Showing posts with label JAX-RS. Show all posts
Showing posts with label JAX-RS. Show all posts

Friday, November 9, 2012

J2EE Application with MOXy

As part of my refactoring of my existing J2EE application using JAX-RS, I wanted to try and reduce the JAXB custom code in place. Previously I was using Jackson and Jersey for JSON serialization using the "Mapped" notation. This involved creating my own JAXBContext object and I was required to create some special mapping processing so that I could map an attribute as etiher an array, non-string or other value.

Since I was going to use the latest version of eclipselink with the refactoring (currently EclipseLink 2.4.1) I decided to check out using MOXy which I had always had my eye on. My goal was to avoid the mapping approach (which was inherently buggy since it required me to remember to add any field to a property file for proper serialization and I could not serialize the same named field differently for different types - ie. field X was always to be type Y). MOXy seemed to like it might be able to address these concerns.

To leverage MOXy in your environment, you need to include it as a provider. In my case I included it in my JAX-RS Application class and set some configuration properties on it. Here is an example of my current application (note I am using Package scanning for JAX-RS resources/providers in Jersey)


public class WebApplication extends PackagesResourceConfig {

 @SuppressWarnings("unused")
 private static final Logger logger = Logger.getLogger(WebApplication.class.getName());

 public WebApplication() {
  super("org.javad.web.providers","org.javad.preferences.model.resources","org.javad.stamp.model.resources");
 }

 @Override
 public Set<Object> getSingletons() {
  MOXyJsonProvider moxyJsonProvider = new MOXyJsonProvider();

  moxyJsonProvider.setAttributePrefix("");
  moxyJsonProvider.setFormattedOutput(true);
  moxyJsonProvider.setIncludeRoot(false);
  moxyJsonProvider.setMarshalEmptyCollections(true);
  moxyJsonProvider.setValueWrapper("$");

  Set<Object> set = new HashSet<Object>();
  set.add(moxyJsonProvider);
  return set;
 }
}

You can read more on the MOXy settings here.

You then need to reference your Application in your web.xml as part of your JAX-RS resource mapping:
<init-param>
    <param-name>javax.ws.rs.Application</param-name>
    <param-value>org.javad.web.WebApplication</param-value>
</init-param>
There are other ways to configure the MOXy configuration, but this is the one that I choose and seemed to fit well for my environment (since I was using a PackageResourceConfig from Jersey for finding my resources).

Since several of my JPA entities included a foreign reference to another JPA entity, I wanted only the ID of the foreign entity to be serialized. Previously I had been using the @XmlIDRef to drive this for serialization, but I had difficulty using this with MOXy. Instead, I needed to declare an XML Adapter to do the serialization and deserialization of the field. This is done using the @XmlJavaTypeAdapter annotation. For my album entity, the foreign key reference to the stamp collection entity looks like this:
@XmlJavaTypeAdapter(StampCollectionRefAdapter.class)
@XmlElement(name = StampFormConstants.STAMP_COLLECTION_REF )
@ManyToOne(optional=false,fetch=FetchType.EAGER)
@JoinColumn(name="COLLECTION_ID",nullable=false)
private StampCollection collection;
In the StampCollectionRefAdapter I transfer the StampCollection entity to an ID and vice versa (when deserializing from a JSON posting). One issue I ran into was that I could not inject the StampCollectionService into this class. This is because these classes are initialized by MOXy (it would appear) prior to the CDI and EntityManagerFactory initialization, so I needed to obtain the EntityManagerFactory which was used in my initialization servlet listener (this sets up a few configurations in my environment). I had tried declaring this class as a @Stateless EJB but did not have any luck (likely because it was constructed explicitly). I may look into this further later, but for now the only way I could get access to the service to transfer the ID back to the physical entity was to leveage the entity manager factory from the initialization listener through a static context (note: this would might fail if I tried to perform any transactions in against this, but should work for normal queries)
public class StampCollectionRefAdapter extends XmlAdapter<StampCollectionRefAdapter.StampCollectionRefType, StampCollection> {

 public StampCollectionRefAdapter() {
  super();
 }
 
 @Override
 public StampCollection unmarshal(StampCollectionRefType v) throws Exception {
  StampCollection collection = null;
  EntityManagerFactory emf = SessionInitializer.getEntityManagerFactory();
  if( emf != null ) {
   EntityManager em = emf.createEntityManager();
   if( em != null ) {
    collection = em.find(StampCollection.class, v.id);
   }
  }
  
  return collection;
 }

 @Override
 public StampCollectionRefType marshal(StampCollection v) throws Exception {
  StampCollectionRefType t = new StampCollectionRefType();
  t.id = v.getId().longValue();
  return t;
 }

 public static class StampCollectionRefType {
  @XmlValue
  public long id;
 }
}

I am having a small issue with arrays of Entities. I have a serializable class which is Genericized and has two fields:
  • total - representing the total number of objects (not necessarily the items returned)
  • items - the List of entities to be returned
The first oddity was I could not define a getItems() method on the abstract class. Instead I had to declare it on the concrete class that implements the Generic type. The reason for this is I want my array of items to be the plural of the actual items contained within it. This requires me to declare the collection similiar to the following:
@XmlRootElement(name="list")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class AlbumModelList extends AbstractModelList<Album> {
 @Override
 @XmlElement(name="albums")
 public List<Album> getItems() {
  return items;
 }
}
The resulting JSON will thus look as I intended:
{
    "total": 5,
    "albums": [
        {
            "id": "2000",
            "name": "Test Collection X",
            "countryRefs": [],
            "stampCollectionRef": 1
        },
        {
            "id": "1",
            "name": "Test Collection x2",
            "countryRefs": [],
            "stampCollectionRef": 1
        },
        {
            "id": "2",
            "name": "Test Collection x4",
            "countryRefs": [],
            "stampCollectionRef": 1
        },
        {
            "id": "3",
            "name": "Test Collection x5",
            "countryRefs": [],
            "stampCollectionRef": 1
        },
        {
            "id": "4",
            "name": "Test Collection x6",
            "countryRefs": [],
            "stampCollectionRef": 1
        }
    ]
}
But if I use a content type of XML (which I am not using very often) the Array is not showing up as am <albums/> element that contains <album/> nodes but instead looks like the following:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<list>
    <total>5</total>
    <albums id="2000">
        <name>Test Collection X</name>
        <stampCollectionRef>1</stampCollectionRef>
    </albums>
    <albums id="1">
        <name>Test Collection x2</name>
        <stampCollectionRef>1</stampCollectionRef>
    </albums>
    <albums id="2">
        <name>Test Collection x4</name>
        <stampCollectionRef>1</stampCollectionRef>
    </albums>
    <albums id="3">
        <name>Test Collection x5</name>
        <stampCollectionRef>1</stampCollectionRef>
    </albums>
    <albums id="4">
        <name>Test Collection x6</name>
        <stampCollectionRef>1</stampCollectionRef>
    </albums>
</list>


Not sure what I am missing here, but I need to address this at some point along with modifying my entity IDs from wrapper types to primitives.




Thursday, November 1, 2012

Diving into J2EE6 with JTA

I have been silent for a long time on the blog (I have been busy - never fear) but simply have not spent the time here to document my activities.

I was in the process of doing a major overhaul on my server-side JAX-RS WEB Services and their accompanying persistence services to bring things up to a little more standard approach. In particular my goals were to:

  1. Utilize more dependency injection (from JSR-299) to avoid having to separately manage my services in a factory.
  2. Utilize JPA using the JTA transactions and a JDBC datasource (I was previously using Resource_Local transaction modes
  3. Inject the EntityManager (or factory - see below)
  4. Leverage in-container testing using Arquillian for the services (to verify the transactional integrity of the services)
  5. Clear out remnants and methods from when the services were used by a Swing Application (which was replaced by Stamp Web 1.0 in 2008)
  6. Leverage MOXy with JAXB for JSON serialization from JAX-RS WEB Services in place o the Jersey implementation with Jackson and mapped notation (which had required me to create custom JABXContext objects, register properties in my custom mapping file etc.)
  7. Provide a proper JAX-RS implementation using Response Builders. Previously I was returning a JSON object with a success flag instead of using valid HTTP Status objects like NOT_FOUND (404)
  8. Provide complete testing of all JAX-RS WEB Service methods in particular using both JSON and XML supported content encodings and verifying all response code for non-conditions.

As you can imagine this has turned out not to be a small effort and I have had to learn and re-learn a lot of areas of J2EE I had convienently left behind in my memory space.

The following is probably the most important points to remember when designing an application like this:

  1. Start small. I didn't simply start modifying my codebase. Instead I started a new project and brought over the highest level concepts (in my case my PersistableObject, AbstractPersistenceService and a few other classes) and built it up from there - testing as I went. This allowed me to verify the new JTA based approach and also let me figure out a few concerns. For example, previously I had to manage all commit/rollback code. Initially I was thinking to mark methods as Transactional and write an interceptor (which led me down a deep hole of Interceptors) only to realize this was not needed in a JTA context.
  2. Early on I read a blog article that stated that you shouldn't use @PersistenceContext (injecting an EntityManager) because it wasn't thread safe and should instead use @PersistenceUnit (injecting an EntityManagerFactory). This seemed like a good idea and worked... until I tried to save 150 stamps (which each created a EntityManager at a lower level of the code). It appears when using JTA and Container Managed transactions (CMT) creating an EntityManager from the factory will establish a different connection in the pool (I couldn't verify this other than I was seeing max-connection errors and deadlocks in my arquillian tests - but only when this test was used). After some reading, I saw that using @PersistenceContext in CMT it becomes the responsibility of the container to close and manage the EntityManagers. Doing so (in place of using the factory to get a new one) instantly rid me of the connection errors and I see a balance of connection threads - Note the test that hit this is one that never happens in my WEB application (yet) but I am glad to have hit this now - rather than after deploying on my production server.
  3. Arquillian took a little effort to get completely working right, but now that I have it working it seems to work nicely for testing my services "in context". I am currently testing my WEB Services using the jersey-client module and running them after my application is deployed to glassfish. I do want to do some further experimentation to see if I can use Arquillian for these (this article looks promising: http://www.samaxes.com/2012/05/javaee-testing-introduction-arquillian-shrinkwrap/)

Along with my services, I am actually going to rewrite my client side application from a GWT/GXT 2 based solution to SmartClient JS. I originally was going to convert to GXT 3, but I have become pretty disillusioned with the roadmap from Sencha, and therefore are planning to go with a JS based client application. In order to pace this, I need to keep the existing GXT 2 + WEB Services running (which is why I am creating a new Web application project) and will be converting/creating client portions on a priority basis. As well, from the services perspective I am attempting to capture a new level of test code coverage (before it was about 45% now I am aiming for 70%+). To accomplish this, I am not writign any WEB Services beyond my first one to ferret out the testing/WADL approaches to prevent me from working on the client code until the server is complete and solid.

Thursday, March 26, 2009

Using JSON with JAXB in new Jersey 1.0.2

Jersey 1.0.2 was released in early February and I just got around to updating to it. I was quite excited to read about the new support for JAXB marshalling to JSON formats (this was introduced I believe in an earlier release but not well detailed). Jakub Podlesak has some nice articles on this functionality on his blog and would recommend reading them. One thing I found, is initially I attempted to use the MAPPED_JETTISON notation in the JSONConfiguration which worked fine with Java JDK 1.6u10. However when I changed this to Natural notation to support my GXT application expected output, I recieved the following error:

javax.xml.bind.JAXBException: property "retainReferenceToInfo" is not supported 
   at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:63) 
   ...


Upon re-reading the dependency notes of Jersey, I noticed the following note: "This module depends on the JAXB reference implementation version 2.1.10 or greater, and such a version is required when enabling support for the JAXB natural JSON convention..." . The version of JAXB shipped with JDK 1.6 is not at a high enough level to support this functionality. Fortuantely the workaround to get this to work is pretty easy if you following the following steps:
  1. Download the JAXB jar from the Jersey depenendencies: jaxb-api-2.1.jarand save this to a local location.
  2. Copy the jaxb-api-2.1.jar to the jre/lib/endorsed folder of your JRE or JDK installation. You may need administrative privileges on some platforms.
  3. Restart eclipse (or other IDE).
  4. In your project class path, include the other JAXB jar files listed under the "non maven developers require... section of the JAXB portion of the document

Information on the endorsed libraries is available here.

Friday, October 3, 2008

Collections and JAX-RS

As I had previously reported, both RestEasy and Jersey both suffered from the inability to return a collection of JAXB marshalled objects. I was thinking on this a little, and while I could use the JAXBCollection fix in Jersey, it seemed a little bit of a hack until it goes into the 1.0 release. Instead (for now), I have written a few wrapper classes which they themselves are XmlRootElements thus supporting marshalling with JAXB. This actually worked and is a reasonable workaround (since I really only need to return collections for four to five persistent objects. These wrapper objects simply have a collection/list of the persistent objects with the XmlElement set to have the appropriate name of the child elements for processing:

package org.javad.stamp.model.collections; import java.util.ArrayList; import java.util.List; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; import org.javad.stamp.model.Country; @XmlRootElement(name="countryList") public class CountryList { @XmlTransient public List countries = new ArrayList(); public CountryList( ) { } public void setCountries( List c ) { countries = c; } @XmlElement(name="country") public List getCountries() { return countries; } public void addCountry( Country c ) { countries.add(c); } }

Deploying RestEasy in Tomcat 6.0

Since I was successful deploying Jersey to Tomcat 6.0, I decided to check out RestEasy from JBoss. One issue I ran into with Jersey was it's inability to XML serialize a collection of objects. This is bug ID is 18, and it is fixed for the 1.0 release (however a beta of this does not appear to be available yet), but I decided to see if RestEasy (a non-reference implementation) has the same issue.

UPDATE I have discovered from some testing that neither XML nor JSON is currently supported as a return type for a Collection/List of items. An issue has been filed for RestEasy for JSON (RESTEASY-134) with an RC1 delivery, however I did not see one for XML.

Here are the steps I used to get this working:

  1. Download RestEasy from the JBoss website: http://www.jboss.org/resteasy/
  2. Follow the steps 2 to 4 of my previous blog Deploying Jersey in Tomcat 6.0
  3. Download and create a Eclipse library for JavaAssist. Include this in your WEB project (or provide the javaassist.jar for Tomcat)
  4. Create a new RestEasy library in eclipse which contains the content of the rest easy installation lib location. You can probably skip a few of the jars if you do not need all the functionality (such as jyaml.jar and possibly mail.jar)
  5. Modify your web.xml for your project to include the following (this comes right from the sample web.xml in the rest easy install):

    <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>TestWeb</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> <context-param> <param-name>resteasy.scan</param-name> <param-value>true</param-value> </context-param> <!-- set this if you map the Resteasy servlet to something other than /* <context-param> <param-name>resteasy.servlet.mapping.prefix</param-name> <param-value>/resteasy</param-value> </context-param> --> <!-- if you are using Spring, Seam or EJB as your component model, remove the ResourceMethodSecurityInterceptor --> <context-param> <param-name>resteasy.resource.method-interceptors</param-name> <param-value> org.jboss.resteasy.core.ResourceMethodSecurityInterceptor </param-value> </context-param> <listener> <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class> </listener> <servlet> <servlet-name>Resteasy</servlet-name> <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class> </servlet> <servlet-mapping> <servlet-name>Resteasy</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
  6. Start your tomcat in Eclipse and you should be good to go!

Thursday, October 2, 2008

Deploying Jersey in Tomcat 6.0

Jersey is a reference implementation for the JAX-RS (JSR-311) for building RESTful Web services. It is nearing approval with the JSR committees. While there are many wikis and articles in using Jersey with Netbeans (downloading the Netbeans 6.1 EE package includes everything you need for JSR-311), there was very little information on using Tomcat 6.0 with Jersey. After piecing together several blogs, I was able to get a simple resource working in Tomcat using JSR-311.

The following are the steps I used to get this working:

  1. Download and unjar the Jersey distribution (I used 0.8) from https://jersey.dev.java.net/ to a location on your system (lets call it JERSEY_HOME for this article).
  2. Download and install the Java-WS distribution (I used 2.1) from https://jax-ws.dev.java.net/. (lets call it JAXWS_HOME for this article).
  3. Rama Pulavarthi wrote a blog (in fact the key for me) in configuring tomcat to reference the Jersey distribution jars. To summarize, in TOMCAT_HOME/conf/catalina.properties modify the shared.loader property entry to point to your JAXWS_HOME/lib/*.jar. Mine looks like this:

    shared.loader=C:/dev/jaxws-ri/lib/*.jar
  4. Create a new Dynamic Web Project in Eclipse using Tomcat 6.0 as the application server.
  5. Create a new library in which you add the following JARs:
    1. JERSEY_HOME/lib/asm-3.1.jar
    2. JERSEY_HOME/lib/jersey.jar
    3. JERSEY_HOME/lib/jsr311-api.jar
  6. Next modify the web.xml to include the adaptor for jersey. Most of the Blogs refer to a different class than what appears in 0.8 I am not certain which is the right class, only the following works for me (and the documented one is not available throught the downloads!):

    <servlet> <servlet-name>ServletAdaptor</servlet-name> <servlet-class>com.sun.jersey.impl.container.servlet.ServletAdaptor</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>ServletAdaptor</servlet-name> <url-pattern>/resources/*</url-pattern> </servlet-mapping> <session-config> <session-timeout>30</session-timeout> </session-config>
  7. If you start Tomcat, you will see the following error:

    com.sun.jersey.api.container.ContainerException: The ResourceConfig instance does not contain any root resource classes.

    This error is due to not providing any root RESTful resources.

  8. Create a new class and include the following:

    import javax.ws.rs.GET; import javax.ws.rs.ProduceMime; import javax.ws.rs.Path; @Path("/test") public class TestResource { @GET @ProduceMime("text/html") public String getMessage( ) { return "hello"; } }
  9. Start and test the application with the following url:

    http://localhost:8080/appName/resources/test

    and you should see a hello in your web-browser.