slifty slifty - 28 days ago 4
Java Question

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>

Answer

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>
    
  • Then as @Alexey Gavrilov pointed out, add the Jackson provider

    <dependency>
        <groupId>com.fasterxml.jackson.jaxrs</groupId>
        <artifactId>jackson-jaxrs-json-provider</artifactId>
        <version>2.6.0</version>
    </dependency>
    
  • You can register this provider by adding the package to the packages to scan

    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>
            org.example.webservice.impl,
            com.fasterxml.jackson.jaxrs.json
        </param-value>
    </init-param>
    

Another thing that is unrelated to this issue that I might point out, is that Glassfish 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