Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get Wildfly to use additional Jackson Datatypes?

I'm getting this error

03:33:14,938 WARN  [org.jboss.resteasy.core.ExceptionHandler] (default task-1) Failed executing PUT /individual/5a247ce9-0a73-4373-89ce-e4177f911259/activities/432e6e5b-4185-462f-b57e-9ec04bec3d58: org.jboss.resteasy.spi.ReaderException: org.codehaus.jackson.map.JsonMappingException: Can not instantiate value of type [simple type, class java.time.Instant] from JSON String; no single-String constructor/factory method (through reference chain: com.lm.activity.DTOActivity["created"])

It's because Wildfly doesn't know how to handle an instant. By reading the error I could simply handle it in that class, but that seems silly. I'm using the following library and am shipping it and all of an updated jackson in my war file, but that alone isn't doing it.

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.3.2</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.3.2</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>2.3.2</version>
    </dependency>

I found this wiki

but my implementation is problematic, the class definition statement has an error

package com.lm.infrastructure;

import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

@Provider
@Produces( MediaType.APPLICATION_JSON )
public class JacksonProducer implements ContextResolver<ObjectMapper> {

    public JacksonProducer() throws Exception {
        this.json = new ObjectMapper()
                .findAndRegisterModules()
                .configure( FAIL_ON_UNKNOWN_PROPERTIES, false );

    }

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

I put this in my web.xml (not to be confused with jboss-web.xml)

<web-app ...
  <context-param>
    <param-name>resteasy.providers</param-name>
    <param-value>com.lm.infrastructure.JacksonProducer</param-value>
  </context-param>
</web-app>

I tried modifying modules/system/layers/base/com/fasterxml/jackson/jaxrs/jackson-jaxrs-json-provider/main/module.xml which seems to be suggested here

 <module xmlns="urn:jboss:module:1.1" name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider">
 <resources>
    <resource-root path="jackson-jaxrs-json-provider-2.3.2.jar"/>
    <resource-root path="jackson-jaxrs-base-2.3.2.jar"/>
    <resource-root path="jackson-module-jaxb-annotations-2.3.2.jar"/>
    <resource-root path="jackson-databind-2.3.2.jar"/>
    <resource-root path="jackson-datatype-jsr310-2.3.2.jar"/>
    <!-- Insert resources here -->
</resources>

<dependencies>
    <module name="javax.api"/>
    <module name="javax.ws.rs.api"/>
    <module name="javax.xml.bind.api"/>
    <module name="com.fasterxml.jackson.core.jackson-annotations"/>
    <module name="com.fasterxml.jackson.core.jackson-core"/>
    <module name="com.fasterxml.jackson.core.jackson-databind"/>
    <module name="com.fasterxml.jackson.datatype.jackson-datatype-jsr310"/>
</dependencies>
</module>

My primary goal is to get jsr310 serializing and deserializing. What do I need to do to make this happen? but I suspect that the answer would apply to any additional datatype that doesn't ship with wildfly. (I think this issue is related )

like image 228
xenoterracide Avatar asked Mar 02 '14 09:03

xenoterracide


People also ask

What is the use of Jackson datatype JSR310?

As already mentioned, Jackson-Datatype-JSR310 provides support for Java 8 Time. You have to register the module like this: ObjectMapper mapper = new ObjectMapper(); mapper.

What is JBoss deployment structure XML?

JBoss Deployment Structure File xml is a JBoss specific deployment descriptor that can be used to control class loading in a fine grained manner. It should be placed in the top level deployment, in META-INF (or WEB-INF for web deployments). It can do the following: Prevent automatic dependencies from being added.

What are WildFly modules?

A WildFly module is a collection of classes and other resources packaged in a set of JAR files, along with the specification for it. The module specification exposes what the module exports or imports from other modules.


2 Answers

Ultimately I was affected by This Bug in 8.0.0.Final it should be fixed in 8.0.1, until then I've downgraded to 8.0.0.CR1.

Here's my Final pom.xml, note that I'm using 2.2.3

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.2.3</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.2.3</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.2.3</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>2.2.3-beta5</version>
    </dependency>

my web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
 ...
    <context-param>
        <param-name>resteasy.providers</param-name>
        <param-value>com.lm.infrastructure.JacksonProducer</param-value>
    </context-param>
</web-app>

my jboss-deployment-structure.xml this is required, and I didn't have it previously

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
        <deployment>
                <exclusions>
                        <module name="org.jboss.resteasy.resteasy-jackson-provider" />
                        <module name="org.jboss.resteasy.resteasy-jettison-provider" />
                </exclusions>
                <dependencies>
                        <module name="org.jboss.resteasy.resteasy-jackson2-provider" services="import" />
                </dependencies>
        </deployment>
</jboss-deployment-structure>

My Producer

package com.lm.infrastructure;

import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
import com.fasterxml.jackson.databind.ObjectMapper;
import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

@Provider
@Produces( MediaType.APPLICATION_JSON )
public class JacksonProducer implements ContextResolver<ObjectMapper> {

    public JacksonProducer() throws Exception {
        this.json
            = new ObjectMapper()
            .findAndRegisterModules()
            .configure( WRITE_DATES_AS_TIMESTAMPS, false )
            .configure( FAIL_ON_UNKNOWN_PROPERTIES, false );
    }

    @Override
    public ObjectMapper getContext( Class<?> objectType ) {
        return json;
    }

    private final ObjectMapper json;
}

and last but not least my arquillian war generation

public static WebArchive testWar() {
    File[] libs
            = Maven.resolver().loadPomFromFile( "pom.xml" )
            .resolve(
                    "com.fasterxml.jackson.datatype:jackson-datatype-jsr310"
            )
            .withTransitivity()
            .asFile();

    return ShrinkWrap.create( WebArchive.class )
            .setWebXML( new File( "src/main/webapp/WEB-INF/web.xml" ) )
            .addAsWebInfResource( new File( "src/main/webapp/WEB-INF/jboss-web.xml" ) )
            .addAsWebInfResource( new File( "src/main/resources/logback.xml" ) )
            .addAsWebInfResource( new File( "src/main/webapp/WEB-INF/jboss-deployment-structure.xml" ) )
            .addAsWebInfResource( EmptyAsset.INSTANCE, "beans.xml" )
            .addPackages( false, Filters.exclude( ".*Test.*" ), getCorePackages() )
            .addAsLibraries( libs );
}
like image 127
xenoterracide Avatar answered Oct 24 '22 03:10

xenoterracide


WildFly 10

For getting the extra datatypes to work under WildFly 10 I also created a file jboss-deployment-structure.xml, but with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
  <deployment>
    <dependencies>
      <module name="com.fasterxml.jackson.datatype.jackson-datatype-jsr310" services="import" />
      <module name="com.fasterxml.jackson.datatype.jackson-datatype-jdk8" services="import" />
    </dependencies>
  </deployment>
</jboss-deployment-structure>

This allowed me to use the classes Jdk8Module and JavaTimeModule.

like image 43
Sander Knopper Avatar answered Oct 24 '22 02:10

Sander Knopper