Tell Jersey generate proper JSON documents (natural json). I use same class for rest app and JAXBContext resolver, found it the most clean encapsulation.
Better programmer could implement helper to iterate .class files and list appropriate classes automatically by identifying @Annotation tags. I don't know how to do it runtime in an own source code.
These two links were helpful studying this extra java jargon. I don't know why there is no Jersey parameter to make all just work out of the box.
WEB-INF/web.xml (snippet):
<servlet>
<servlet-name>RESTServlet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.myapp.rest.RESTApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>RESTServlet</servlet-name>
<url-pattern>/servlet/rest/*</url-pattern>
</servlet-mapping>
com.myapp.rest.RESTApplication.java
package com.myapp.rest;
import java.util.*;
import javax.ws.rs.core.Application;
import javax.ws.rs.ext.ContextResolver;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import com.sun.jersey.api.json.JSONConfiguration;
import com.sun.jersey.api.json.JSONJAXBContext;
public class RESTApplication extends Application implements ContextResolver<JAXBContext> {
private JAXBContext context;
private Class<?>[] types;
public RESTApplication() throws JAXBException {
// list JAXB bean types to be used for REST serialization
types = new Class[] {
com.myapp.rest.MyBean1.class,
com.myapp.rest.MyBean2.class,
};
context = new JSONJAXBContext(JSONConfiguration.natural().build(), types);
}
@Override
public Set<Class<?>> getClasses() {
// list JAXB resource/provider/resolver classes
Set<Class<?>> classes = new HashSet<Class<?>>();
//for(Class<?> type : types)
// classes.add(type);
classes.add(MyBeansResource.class);
classes.add(this.getClass()); // used as a ContextResolver class
return classes;
}
@Override
public JAXBContext getContext(Class<?> objectType) {
// this is called each time when rest path was called by remote client
for (Class<?> type : types) {
if (type==objectType)
return context;
}
return null;
}
}
Classes MyBean1,MyBean2 are plain java objects and MyBeansResource class is the one with @Path rest functions. There is nothing special in them expect standard jaxp @Annotations here and there. After this java jargon JSON documents have
- zero or single-element List arrays are always written as json array ([] field)
- primitive integers and boolean fields are written as json primitives (without quotations)
I use the following environment
- Sun Java JDK1.6.x
- Apache Tomcat 6.x
- Jersey v1.14 libraries (jersey-archive-1.14.zip)
- webapps/myapp/WEB-INF/lib folder has asm-3.3.1.jar, jackson-core-asl.jar, jersey-client.jar, jersey-core.jar, jersey-json.jar, jersey-server.jar, jersey-servlet.jar libraries
- add optional annotation-detector.jar if you use infomas-asl discovery tool
jersey-archive.zip had older asm-3.1.jar file, probably works fine but chapter_deps.html links to a newer file. See link list at the top.
Edit
I found an excellent(fast, lightweight just 15KB) annotation discovery tool. See this post about how I autodiscover types at runtime and no longer need to edit RESTApplication each time new java(jaxb) bean is added.
https://github.com/rmuller/infomas-asl/issues/7