Dr4gon Dr4gon - 1 month ago 21
reST (reStructuredText) Question

MessageBodyWriter not found for media type=application/json with GF4 and Jackson

I got the following error message every time I try to call my REST service

[2016-09-01T16:27:37.782+0200] [Payara 4.1] [SEVERE] [] [org.glassfish.jersey.message.internal.WriterInterceptorExecutor] [tid: _ThreadID=28 _ThreadName=http-listener-1(3)] [timeMillis: 1472740057782] [levelValue: 1000] [[MessageBodyWriter not found for media type=application/json, type=class xxx.JsonClass, genericType=class xxx.JsonClass.]]


Here's the REST service (stripped to the relevant part):

import javax.ejb.EJB;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;


@Path("/service")
public class Service {

@GET
@Path("/callme")
@Produces(MediaType.APPLICATION_JSON)
public JsonClass callme(//
@QueryParam("test") final String test, //
....) {
return new JsonClass();
}
}


The JSON Class

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

public class JsonClass {

private String test;

public JsonClass(final String test....) {
...
}

@JsonProperty
public String getTest() {
return this.test;
}
}


POM.xml (interesting parts)

<!-- DO NOT change the scope for jersey: https://java.net/jira/browse/JERSEY-1941 -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.8</version>
<scope>provided</scope>
</dependency>


My setup is:


  • JDK8/JEE7 (build 1.8.0_51-b16)

  • Glassfish 4.1 Payara

  • Maven 3.2.5



This is what I tried so far:



I still think it's a dependency problem here. However I'm out of ideas what could be the problem.

Answer

Unfortunately my last post was marked as duplicate although the problem and the solution was different. Therefore I'm posting a new question with the two solutions to hopefully help you avoid head banging at the table for several hours.

Preferred solution:

Apparently GF4 ships with MoxyJson which I didn't want to use. To integrate your own dependency - in my case Jackson - you need to disable the MoxyJson with the below code.

@ApplicationPath("/")
public class ApplicationConfig extends Application {

  /**
   * {@inheritDoc}
   */
  @Override
  public Map<String, Object> getProperties() {
    final Map<String, Object> properties = new HashMap<String, Object>();
    properties.put("jersey.config.server.disableMoxyJson", true);

    return properties;
  }
}

Then add your own dependencies, e.g. in my case only those two because the others are referenced by another lib I use.

<dependency>
  <groupId>com.fasterxml.jackson.jaxrs</groupId>
  <artifactId>jackson-jaxrs-json-provider</artifactId>
  <version>2.6.2</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.dataformat</groupId>
  <artifactId>jackson-dataformat-xml</artifactId>
  <version>2.6.2</version>
</dependency>

Finally I made the mistake of not setting a value to the @JsonProperty annotations which will cause a No MessageBodyWriter found exception. To avoid that use the following ony relevant getters of your class.

@JsonProperty("randomName")
public String getRandomName(){
...
}

Alternative:

Worse than above you'll need to disable MoxyJson, register each service individually, and fix a Bug when using ResourceConfig of GF.

@ApplicationPath("/")
public class ApplicationConfig extends ResourceConfig {

/**
* The default constructor.
*/
public ApplicationConfig() {

// Disable Moxy and use Jackson
this.property(ServerProperties.MOXY_JSON_FEATURE_DISABLE, true);

// Register own provider classes
this.register(Fully.Qualified.Path.To.Your.Service.class);

// Register Jackson provider
// Workaround for GF4.1 bug for details: https://java.net/jira/browse/GLASSFISH-21141
final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JaxbAnnotationModule());
this.register(new JacksonJaxbJsonProvider(mapper, JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS));
}
}

You'll need an additional dependency for the ResourceConfig class.

 <dependency>
  <groupId>com.fasterxml.jackson.jaxrs</groupId>
  <artifactId>jackson-jaxrs-json-provider</artifactId>
  <version>2.6.2</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.dataformat</groupId>
  <artifactId>jackson-dataformat-xml</artifactId>
  <version>2.6.2</version>
</dependency>

<dependency>
  <groupId>org.glassfish.main.extras</groupId>
  <artifactId>glassfish-embedded-all</artifactId>
  <version>4.1.1</version>
  <scope>provided</scope>
</dependency>

Finally the same as above - be aware to use @JsonProperty with a set value.