Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Jersey ignoring my Jackson annotations?

I'm using Jersey and Jackson to create a simple JSON API.

Some of the objects being serialized have custom enum fields. By default, those enums are converted to a string based on the enum vale -- I would like the enums to have slightly more complex serializations.

I'm using Jackson annotations within the enum, but the endpoint seems to be ignoring them. I've been spinning my wheels trying to figure out where the issue is, and now I turn to you.

Enum Code

package org.example.code;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonFormat(shape= JsonFormat.Shape.OBJECT)
public enum ExampleEnum {
    YES (1, "Yes indeed"),
    NO (2, "No way buddy")

    private final Integer code;
    private final String description;

    ExampleEnum(final Integer code, final String description) {
        this.code = code;
        this.description = description;
    }

    @JsonProperty("code")
    public Integer getCode() {
        return code;
    }
    @JsonProperty("description")
    public String getDescription() {
        return description;
    }
}

API Code

package org.example.webservice.impl;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.example.code.ExampleEnum;


@Path("/example")
public class ExampleService {   
    @GET
    @Path("/test")
    @Produces({MediaType.APPLICATION_JSON})
    public ExampleEnum getExampleEnum() {
        return ExampleEnum.YES;
    }
}

When I call the endpoint example/test the output is YES What I want is the output to be something along the lines of { code: 1, description: "Yes indeed" }

Configuration files are below...

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>api</artifactId>
    <version>0.0.1</version>
    <packaging>war</packaging>

    <name>example API</name>
    <url>http://example.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <dependency>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
            <version>2.0.1</version>
        </dependency>

        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.2</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.6.0</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet-core</artifactId>
            <version>2.18</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <url>http://localhost:8080/manager/text</url>
                    <server>TomcatServer</server>
                    <path>/example</path>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <display-name></display-name> 
  <servlet>
    <display-name>Example Servlet</display-name>
    <servlet-name>Example Servlet</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>org.example.webservice.impl</param-value>
    </init-param>
    <init-param>
        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
      <param-name>jersey.config.server.provider.classnames</param-name>
      <param-value>org.glassfish.jersey.filter.LoggingFilter;org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Example Servlet</servlet-name>
    <url-pattern>/services/*</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>
like image 553
slifty Avatar asked Jul 24 '15 18:07

slifty


3 Answers

So a Few things:

  • com.sun.jersey.api.json.POJOMappingFeature is for Jersey 1.x, so you can get rid of that.

  • MOXy is the default provider in Glassfish, so if you want to use Jackson, then you need to disable MOXy. You can do so by adding this <init-param>

    <init-param>
        <param-name>jersey.config.server.disableMoxyJson</param-name>
        <param-value>true</param-value>
    </init-param>
    

    If you are using a ResourceConfig for your configuration, you can use the property

    public class JerseyConfig extends ResourceConfig {
        public JerseyConfig() {
            property(ServerProperties.MOXY_JSON_FEATURE_DISABLE, true);
        }
    }
    

    The constant value is actually jersey.config.server.disableMoxyJson.

  • Then add the Jackson provider

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>${jersey2.version}</version>
        <scope>provided</scope>
    </dependency>
    

    The Jersey version should match whatever version you are using for your project. One very important thing to note though is that if you are using Glassfish, you SHOULD put all your Jersey dependencies in a <scope>provided</scope> because the server already has the jars in its library. You do not want your project dependencies to conflict with the jars that are already in the server.

  • Next you need to register the Jackson provider with your app. If you are using web.xml you can add the JacksonFeature to the list on the ...classnames property

    <init-param>
        <param-name>jersey.config.server.provider.classnames</param-name>
        <param-value>
            org.glassfish.jersey.filter.LoggingFilter,
            org.glassfish.jersey.media.multipart.MultiPartFeature,
            org.glassfish.jersey.jackson.JacksonFeature
        </param-value>
    </init-param>
    

    If you are using a ResourceConfig for your configuration, then you can just register the JacksonFeature

    public class JerseyConfig extends ResourceConfig {
        public JerseyConfig() {
            register(JacksonFeature.class);
        }
    }
    

Another thing that is unrelated to this issue that I might point out, is that Glassfish 4 already has a Jersey implementation, which is a very old 2.x version, maybe 2.0. When you add runtime Jersey dependencies, they might conflict. I would do one of two things, either put all the Jersey dependencies in a provided <scope> or if you have requirements for later version functionality, you may want to look into updating the Jersey version in Glassfish. Have a look at Updating Jersey 2 in GlassFish 4

like image 112
Paul Samsotha Avatar answered Sep 30 '22 15:09

Paul Samsotha


Glassfish has jackson jar within itself and it may have conflicts with explicit jackson jars that you have declared in pom.xml .

In maven website, for each version of the jar, there are few other compile time dependencies jars within the jar you have chosen.

So those might also be conflicting with the jars that you have declared in pom.xml

enter image description here

I also removed

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>2.24</version>
</dependency>

from pom.xml

like image 42
sofs1 Avatar answered Sep 30 '22 16:09

sofs1


For Jersey 2.2x users who use Application class rather than using web.xml, this works for me

1. In ResourceConfig,

@ApplicationPath("rest")
public class JerseyApplication  extends ResourceConfig {
    public JerseyApplication() {
        packages("com.example.rest");
        register(JacksonFeature.class);                       
    }
}

Or, if you are using Application class,

public class MyApplication extends Application {

    public Set<Class<?>> getClasses() {
        final Set<Class<?>> classes = new HashSet<Class<?>>();
        .
        .
        classes.add(JacksonFeature.class);
        return classes;
    }
}

2. In pom.xml, add this dependency,

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>2.26</version>
</dependency>

3. Make sure you have annotations on getters and setters as well. In my case @JsonIgnore annotation worked only when I used it on getter and setter of that class variable.

like image 45
okcomputer_kid Avatar answered Sep 30 '22 16:09

okcomputer_kid