How do I use the Jersey JSON POJO support?
Solution 1
Jersey-json has a JAXB implementation. The reason you're getting that exception is because you don't have a Provider registered, or more specifically a MessageBodyWriter. You need to register a proper context within your provider:
@Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext> {
private final static String ENTITY_PACKAGE = "package.goes.here";
private final static JAXBContext context;
static {
try {
context = new JAXBContextAdapter(new JSONJAXBContext(JSONConfiguration.mapped().rootUnwrapping(false).build(), ENTITY_PACKAGE));
} catch (final JAXBException ex) {
throw new IllegalStateException("Could not resolve JAXBContext.", ex);
}
}
public JAXBContext getContext(final Class<?> type) {
try {
if (type.getPackage().getName().contains(ENTITY_PACKAGE)) {
return context;
}
} catch (final Exception ex) {
// trap, just return null
}
return null;
}
public static final class JAXBContextAdapter extends JAXBContext {
private final JAXBContext context;
public JAXBContextAdapter(final JAXBContext context) {
this.context = context;
}
@Override
public Marshaller createMarshaller() {
Marshaller marshaller = null;
try {
marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
} catch (final PropertyException pe) {
return marshaller;
} catch (final JAXBException jbe) {
return null;
}
return marshaller;
}
@Override
public Unmarshaller createUnmarshaller() throws JAXBException {
final Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.setEventHandler(new DefaultValidationEventHandler());
return unmarshaller;
}
@Override
public Validator createValidator() throws JAXBException {
return context.createValidator();
}
}
}
This looks up for an @XmlRegistry
within the provided package name, which is a package that contains @XmlRootElement
annotated POJOs.
@XmlRootElement
public class Person {
private String firstName;
//getters and setters, etc.
}
then create an ObjectFactory in the same package:
@XmlRegistry
public class ObjectFactory {
public Person createNewPerson() {
return new Person();
}
}
With the @Provider
registered, Jersey should facilitate the marshalling for you in your resource:
@GET
@Consumes(MediaType.APPLICATION_JSON)
public Response doWork(Person person) {
// do work
return Response.ok().build();
}
Solution 2
You can use @XmlRootElement
if you want to use JAXB annotations (see other answers).
However, if you prefer pure POJO mapping, you must do the following (Unfortunately it isn't written in docs):
- Add jackson*.jar to your classpath (As stated by @Vitali Bichov);
- In web.xml, if you're using
com.sun.jersey.config.property.packages
init parameter, addorg.codehaus.jackson.jaxrs
to the list. This will include JSON providers in the scan list of Jersey.
Solution 3
This did it for me - Jersey 2.3.1
In the web.xml file :
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value><my webapp packages>;org.codehaus.jackson.jaxrs</param-value>
</init-param>
</servlet>
In the pom.xml file :
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.3.1</version>
</dependency>
Solution 4
I followed the instructions here which show how to use Jersey and Jackson POJOs(as opposed to JAXB). It worked with Jersey 1.12 as well.
Solution 5
You've probably already figured this out, but all you need to do is add these jackson jars to your classpath: jackson-core, jackson-jaxrs, jackson-mapper, and jackson-xc
It appears that there is another way, as others have noted. Add this to your "com.sun.jersey.config.property.packages" parameter (if using tomcat and web.xml): "org.codehaus.jackson.jaxrs", like so:
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>org.codehaus.jackson.jaxrs</param- value>
</init-param>
Doing this will also require the same jackson jars on your classpath
Nick
Updated on March 25, 2021Comments
-
Nick about 3 years
I have an object that I'd like to serve in JSON as a RESTful resource. I have Jersey's JSON POJO support turned on like so (in web.xml):
<servlet> <servlet-name>Jersey Web Application</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
But when I try to access the resource, I get this exception:
SEVERE: A message body writer for Java type, class com.example.MyDto, and MIME media type, application/json, was not found SEVERE: Mapped exception to response: 500 (Internal Server Error) javax.ws.rs.WebApplicationException ...
The class that I'm trying to serve isn't complicated, all it's got are some public final fields and a constructor that sets all of them. The fields are all strings, primitives, classes similar to this one, or Lists thereof (I've tried using plain Lists instead of generic List<T>s, to no avail). Does anyone know what gives? Thanks!
Java EE 6
Jersey 1.1.5
GlassFish 3.0.1
-
Nick about 13 yearsThanks! I've been able to get it working with JAXB, but I'm specifically looking for Jersey POJO writing, not JAXB writing. Would having final fields interfere with that? I have final fields because they represent immutable properties of the object.
-
Nick about 13 yearsThanks! Looks like I misunderstood how Jersey JSON/POJO works.
-
Bhavesh over 11 yearsHey smiths, though its answered am concerned about version 1.12. In v1.12 of jersey-json does not have POJOMappingFeature classs. Do we need to add any additional jar or need to alter the configuration for latest versions of Jersey. It seems on official jersey site (jersey.java.net/nonav/documentation/latest/json.html) the documentation is pretty old. Kindly guide me because I don't want to add unnecessary JAXB annotation @XMLRootElement to my POJO's. Thanks.
-
Nilzor over 11 yearsJust for the record - this answer is no longer valid for v1.18 of Jersey. You do NOT need to write your own MessageBodyWriter and the return type of your @GET methods can be POJO-objects.
-
demaniak about 11 yearsFYI, if using maven, this will pull it in for you:
<dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-json</artifactId> <version>1.8</version> </dependency>
-
HappyCoder86 almost 11 yearsNice... I totally forgot to add the @XmlRootElement to a class in my project. Thanks!
-
Ace Gamer over 10 yearsOMG thanks. The magic extra packages to scan fixed it for me. I had followed all the other related posts regarding class paths and manual provider registration. Thanks again.
-
Pavlonator over 10 yearsthis worked for me, with only one correction that param-name has to be com.sun.jersey.config.property.packages
-
Claire Sannier about 10 yearsThis was my solution.
-
Claire Sannier about 10 yearsSeconding @Nilzor - Excellent question but this is no longer the best answer.
-
Nilzor about 10 yearsYes and to underline, if you get this issue today your problem is most likely a classpath-issue, as mentioned in other answers here.
-
AechoLiu over 9 yearsI add the
jersey-media-json-jackson
fromMaven
. It works. Thank you very much. -
Neo almost 9 years@Pavlonator, if you are using JAXRS-2.0, the
param-name
isjersey.config.server.provider.packages
and if you are still on 1.x, theparam-name
is com.sun.jersey.config.property.packages