13

I'm implementing REST web service with Jersey 2.6,

I'm having troubles of registering a Jackson Provider for JSON support, I have implemented according to the jeresy documentation (https://jersey.java.net/documentation/2.6/user-guide.html#json.jackson).

  1. Add maven dependency - jersey-media-json-jackson
  2. Implemented a ContextResolver class.
  3. Annotated it with @Provider to enable "Auto-Discoverable Features"
  4. web.xml has the package name of the provider classes, so that Providers will be registered during the scan.

ref: http://blog.dejavu.sk/2013/11/19/registering-resources-and-providers-in-jersey-2/

For some reason Jackson JSON provider is not registered, am I missing something?

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
Asela Senanayake
  • 351
  • 2
  • 6
  • 21

3 Answers3

16

Up until Jersey 2.9, that feature is not auto-discovered. We need to either (1) explicitly register the JacksonFeature in the Application/ResourceConfig subclass, (2) list the Jackson package in the web.xml of packages to scan, or (3) add the JacksonFeature to the list of providers in the web.xml

Application subclass:

public class MyApplication extends ResourceConfig {  
    public MyApplication() {
        // (1)
        register(JacksonFeature.class); // <----- Jackson Support
        packages("the.package.of.your.resources");
    }
}

Or web.xml:

<servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>
        org.glassfish.jersey.servlet.ServletContainer
    </servlet-class>
    <init-param>
        <!-- (2) -->
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>
            the.package.of.your.resources,
            org.codehaus.jackson.jaxrs <!-- Jackson providers -->
        </param-value>
    </init-param>
    <init-param>
        <!-- (3) -->
        <param-name>jersey.config.server.provider.classnames</param-name>
        <param-value>
            org.glassfish.jersey.jackson.JacksonFeature
        </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

See more details here in the "Second Issue". Note that for the ...classnames property, if you have more than one provider to register, you should list it in the same param-value delimited with a comma, semicolon, or newline.

Oh and just an FYI, the ContextResolver is only to register the ObjectMapper in a retrievable context, so the MessageBodyReader/MessageBodyWriters can reuse it. But it does not register the actual MessageBodyReader/Writer that is required for the marshalling/unmarshalling.

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • Grate, I have missed the "org.codehaus.jackson.jaxrs" in web.xml, now it's trying to load the jackson libraries, but i'm getting following error java.lang.NoClassDefFoundError: org/codehaus/jackson/map/JsonMappingException – Asela Senanayake Jan 14 '15 at 05:11
  • When do you get that? On start up or when you try and send a request? – Paul Samsotha Jan 14 '15 at 05:14
  • Did you try and add any other Jackson dependencies aside from the Jersey one? – Paul Samsotha Jan 14 '15 at 05:16
  • On startup, no other dependencies added other than jersey. – Asela Senanayake Jan 14 '15 at 05:18
  • Hmm, what are you deploying to? A servlet container like Tomcat or a EE server? – Paul Samsotha Jan 14 '15 at 05:20
  • 1
    I wish I could test it but I don't use Weblogic. Do you know if Weblogic still uses Jersey 1? Maybe it's a conflict. If that's the case, I don't know how to make your server ignore the Jersey 1. You might want to look into that. – Paul Samsotha Jan 14 '15 at 05:22
  • 2
    You can also check what Jackson version the Server uses. You can try and remove the artifacts from the server. It may be that it is loading older Jackson version. But again I am not sure, just throwing some ideas as to what you can try, and look for – Paul Samsotha Jan 14 '15 at 05:30
  • 2
    you were spot on, there is a older version of jackson is added to ear with some other dependency, it works as charm once it is removed. – Asela Senanayake Jan 14 '15 at 05:48
  • In my case, when jackson and jsonb were both on classpath, jsonb was registered so my ObjectMapper provider did not work anymore. Explicitely registering JacksonFeature made jackson work again. In case jsonb is not on classpath jersey was smart enough to automatically register JacksonFeature. – cen Sep 16 '20 at 08:39
2

Hi I don't think above is good solution. Since i faced the same issue where jersey springboot jackson has to be provided.

here above JacksonFeature.class is from glassfish which has less feature which is problem for springboot application in future

  public class MyApplication extends ResourceConfig {  
     public MyApplication() {
    // (1)
    register(ObjectMapperContextResolver.class); // <----- Jackson Support
    packages("the.package.of.your.resources");
}
}


import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import org.springframework.beans.factory.annotation.Autowired;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {

private final ObjectMapper mapper;

public ObjectMapperContextResolver() {
mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}

@Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}

}

Important point is you need to import ObjectMapper as com.fasterxml.jackson.databind.ObjectMapper; for latest springboot Jackson

0

Just in case someone is looking for what worked on Weblogic 12.2.1.4 and CXF Servlet 2.7.11 for producing (serializing) JSON using JacksonProvider. This solution is pretty much same as above by Paul Samsotha (thanks a bunch btw!), but everything is mentioned in one place so someone as lost as I was can easily figure it out.

web.xml

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/conf/*-config.xml</param-value>
  </context-param>

  <servlet>
    <servlet-name>CXFServlet</servlet-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    <init-param>
      <param-name>javax.ws.rs.Application</param-name>
      <param-value>com.myproject.common.application.ApplicationConfig</param-value>
    </init-param>       
    <init-param>
      <param-name>jersey.config.server.disableMoxyJson</param-name>
      <param-value>true</param-value>
    </init-param>     
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>org.codehaus.jackson.jaxrs</param-value>
    </init-param>      
    <load-on-startup>1</load-on-startup>
  </servlet>

/WEB-INF/conf/app-config.xml

 <bean id="jsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
        
 <jaxrs:providers>         
    <ref bean="objectMapperContextResolver" />
    <ref bean="jsonProvider" />
 </jaxrs:providers>

Custom ObjectMapper ContextResolver

package com.myproject.common.provider;

import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
import org.springframework.stereotype.Component;

@Component("objectMapperContextResolver")
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
    private final ObjectMapper mapper;
    
    public ObjectMapperContextResolver() {
        mapper = new ObjectMapper();
        mapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, false);
        mapper.setSerializationInclusion(Inclusion.ALWAYS);
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return mapper;
    }    
}

Create App config to register JacksonFuture and custom ObjectMapperContextResolver

package com.myproject.common.application;

import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import org.glassfish.jersey.jackson.JacksonFeature;
import com.myproject.common.provider.ObjectMapperContextResolver;

@ApplicationPath("/")
public class ApplicationConfig extends Application {
  
    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> classes = new java.util.HashSet<>();
        classes.add(JacksonFeature.class);
        classes.add(ObjectMapperContextResolver.class);
        return classes;
    }    
}

Specify Jackson provider package as prefer-application-packages in weblogic-application.xml in my case, can be in web.xml:

<weblogic-application>                
    <prefer-application-packages>
         <package-name>org.codehaus.jackson.jaxrs.*</package-name>
    </prefer-application-packages>
</weblogic-application> 

In the pom.xml exclude any unnecessary jersey dependency and add following org.glassfish.jersey.media jars:

    <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-sse -->
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-sse</artifactId>
        <version>2.0-m10</version>
        <exclusions>
            <exclusion>
                <groupId>org.glassfish.jersey.core</groupId>
                <artifactId>jersey-server</artifactId>
            </exclusion>
        </exclusions>      
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-json-jackson -->
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>2.0-m10</version>
    </dependency>