How do I use the Jersey JSON POJO support?

99,628

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):

  1. Add jackson*.jar to your classpath (As stated by @Vitali Bichov);
  2. In web.xml, if you're using com.sun.jersey.config.property.packages init parameter, add org.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

Share:
99,628
Nick
Author by

Nick

Updated on March 25, 2021

Comments

  • Nick
    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
    Nick about 13 years
    Thanks! 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
    Nick about 13 years
    Thanks! Looks like I misunderstood how Jersey JSON/POJO works.
  • Bhavesh
    Bhavesh over 11 years
    Hey 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
    Nilzor over 11 years
    Just 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
    demaniak about 11 years
    FYI, 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
    HappyCoder86 almost 11 years
    Nice... I totally forgot to add the @XmlRootElement to a class in my project. Thanks!
  • Ace Gamer
    Ace Gamer over 10 years
    OMG 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
    Pavlonator over 10 years
    this worked for me, with only one correction that param-name has to be com.sun.jersey.config.property.packages
  • Claire Sannier
    Claire Sannier about 10 years
    This was my solution.
  • Claire Sannier
    Claire Sannier about 10 years
    Seconding @Nilzor - Excellent question but this is no longer the best answer.
  • Nilzor
    Nilzor about 10 years
    Yes and to underline, if you get this issue today your problem is most likely a classpath-issue, as mentioned in other answers here.
  • AechoLiu
    AechoLiu over 9 years
    I add the jersey-media-json-jackson from Maven. It works. Thank you very much.
  • Neo
    Neo almost 9 years
    @Pavlonator, if you are using JAXRS-2.0, the param-name is jersey.config.server.provider.packages and if you are still on 1.x, the param-name is com.sun.jersey.config.property.packages