7

I have an application that has webservices built with Jersey and Jackson as JSON provider, all this in a Tomcat application server.

I need to make this application working on Wildfly 10 and everything is working fine, beside the webservice response that is not taking in consideration the Jackson annotations. From what I read Wildfly was using Jettison as default and in the newer version Jackson2 is used.

The preferred solution would be to make RestEasy (from Wildfly 10) to use Jackson and for this I tried to exclude Jackson2 and Jettison and make a dependency to Jackson in (META-INF\jboss-deployment-structure.xml), as below:

<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
    <exclusions>
        <module name="org.jboss.resteasy.resteasy-jackson2-provider"/>
        <module name="org.jboss.resteasy.resteasy-jettison-provider"/>
    </exclusions>
    <dependencies>
        <module name="org.jboss.resteasy.resteasy-jackson-provider" services="import"/>
    </dependencies>
</deployment>
</jboss-deployment-structure>

Apparently this is not enough, since is behaving as before. What else should I try?

UPDATE:

Since my application should work the same on both Tomcat (using Jersey) and Wildfly (using RestEasy), I cannot rely on using jackson from resteasy inside my application, hence I'm importing org.codehaus.jackson.

So, I register my application like this:

import javax.ws.rs.core.Application;
public class RestApplication extends Application
{
   @Override
   public Set<Class<?>> getClasses() {
       Set<Class<?>> classes = new HashSet<Class<?>>();

       classes.add(RestObjectMapperProvider.class);
       classes.add(GeneratedService.class);

       return classes;
   }
}

And rest object mapper provider:

import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import org.codehaus.jackson.map.ObjectMapper;
@Provider
public class RestObjectMapperProvider implements ContextResolver<ObjectMapper>
{
   private final ObjectMapper objectMapper;

   public RestObjectMapperProvider()
   {
       this.objectMapper = new ObjectMapper();

       this.objectMapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
   }

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

I'm building my app with Gradle and below is the Jackson dependency:

compile group: 'org.codehaus.jackson', name: 'jackson-jaxrs', version: '1.9.+'

Since under Tomcat (Jersey) the annotation are considered, my guess would be that in Wildfly my exclusions are not considered. Is there any way to check which JSON Provider was considered, beside checking the response?

Alin
  • 111
  • 1
  • 10

2 Answers2

5

I'm curious why you are using Jackson 1.x instead of 2.x? The instructions are similar for both but the Jackson Configuration would have to change. Below are instructions for 1.x.

jboss-deployment-structure.xml (same as yours):

<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
    <exclusions>
        <module name="org.jboss.resteasy.resteasy-jackson2-provider"/>
        <module name="org.jboss.resteasy.resteasy-jettison-provider"/>
    </exclusions>
    <dependencies>
        <module name="org.jboss.resteasy.resteasy-jackson-provider" services="import"/>
    </dependencies>
</deployment>
</jboss-deployment-structure>

Register your application with @Application:

@ApplicationPath("/api/v1")
public class V1Application extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> classes = new HashSet<Class<?>>();

        classes.add(JacksonConfigurationProvider.class);
        classes.add(TestResource.class);

        return classes;
    }

}

Use a jackson configuration provider like:

@Provider
@Consumes({MediaType.APPLICATION_JSON, "text/json"})
@Produces({MediaType.APPLICATION_JSON, "text/json"})
public class JacksonConfigurationProvider extends ResteasyJacksonProvider {

    private static final Logger LOGGER = LoggerFactory.getLogger(JacksonConfigurationProvider.class);

    public JacksonConfigurationProvider() {
        super();

        LOGGER.info("loading jackson configurator");

        JacksonObjectMapper mapper = JacksonObjectMapper.get();
        setMapper(mapper);

    }
}

Then, in your JacksonObjectMapper is where you tell it to read the annotations:

public class JacksonObjectMapper extends ObjectMapper {
    public static JacksonObjectMapper get() {
        JacksonObjectMapper mapper = new JacksonObjectMapper();

        mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
        mapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true);

        JacksonAnnotationIntrospector jacksonAnnotationIntrospector = new JacksonAnnotationIntrospector();
        mapper.setDeserializationConfig(mapper.getDeserializationConfig().withAnnotationIntrospector
                (jacksonAnnotationIntrospector));
        mapper.setSerializationConfig(mapper.getSerializationConfig().withAnnotationIntrospector
                (jacksonAnnotationIntrospector));

        return mapper;
    }
}

My Jackson Object looks like this:

@JsonRootName("foobar")
public class TestType {

    @JsonProperty("goodbye")
    String hello;

    public String getHello() {
        return hello;
    }

    public void setHello(String hello) {
        this.hello = hello;
    }
}

As a convienence I also have this in my web.xml, it allows you to request json by just putting .json on the URL rather than setting headers:

<context-param>
    <param-name>resteasy.media.type.mappings</param-name>
    <param-value>json : application/json, xml : application/xml</param-value>
</context-param>

When I call http://127.0.0.1:8080/api/v1/test.json I get:

{
    "foobar": {
        "goodbye": "Here is some random string"
    }
}

I have posted my full working code here: https://github.com/teacurran/java-experiments/tree/master/stackoverflow-sandbox/Q42416036

Tea Curran
  • 2,923
  • 2
  • 18
  • 22
  • Thanks for your reply. I'm using Jackson1 because this is how the application was developed long time back, I just need to make it compatible with Wildfly with changing the annotations – Alin Feb 24 '17 at 10:13
  • Unfortunately is not working yet. I shared my code (which is similar with yours) with the hope that you might have a clue what can be wrong. I suspect that the exclusions are not considered, but I don't know how to check to confirm this theory 100% (beside REST response) – Alin Feb 26 '17 at 07:51
1

The fix was to put the exclusions and the dependencies in the sub-deployment, instead of deployment tag, as I was doing.

<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<sub-deployment name="axis.war">
    <exclusions>
        <module name="org.jboss.resteasy.resteasy-jackson2-provider"/>
        <module name="org.jboss.resteasy.resteasy-jettison-provider"/>
    </exclusions>
    <dependencies>
        <module name="org.jboss.resteasy.resteasy-jackson-provider" services="import"/>
    </dependencies>
</sub-deployment>

Alin
  • 111
  • 1
  • 10