0
votes

I am getting

MessageBodyWriter not found for media type=application/json, type=class java.util.HashMap$Values, genericType=java.util.Collection

from a web service with Glassfish 4.1. Everything I see says to have the jackson or other library in the classpath so that the types can be converted. With Glassfish, I have:

~/apps/glassfish-4.1/glassfish/domains/domain1/logs$ find ../../../../ | grep jackson
../../../../glassfish/modules/jackson-core.jar
../../../../glassfish/modules/jackson-annotations.jar
../../../../glassfish/modules/jackson-databind.jar
../../../../glassfish/modules/jackson-jaxrs-json-provider.jar
../../../../glassfish/modules/jackson-jaxrs-base.jar
../../../../glassfish/modules/jersey-media-json-jackson.jar

Entity Classes:

public class Actor extends AbstractBaseEntity{
    public Actor(String id, String name) {
        super(id, name);
    }
}

public class AbstractBaseEntity {
    String identifier;
    String name;

    public AbstractBaseEntity(String id, String name){
        this.identifier = id;
        this.name = name;
    }

    public String getIdentifier() {
        return identifier;
    }

    public String getName() {
        return name;
    }
}

Service class:

@Path("actors")
public class MockActorService {
    private static final int DEFAULT_COUNT = 5;
    HashMap<String, Actor> items;
    public MockActorService() throws WFlowServiceException {
        this(MockActorService.DEFAULT_COUNT);
    }

    public MockActorService(int actors) throws WFlowServiceException {
        items = new HashMap<>();
        for (int i = 0; i < actors; i++) {
            Actor a = new Actor("ID:" + i, "Actor Name " + i);
            items.put(a.getIdentifier(), a);
        }
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getAll() throws WFlowServiceException {
        GenericEntity< Collection< Actor > > entity;
        Collection<Actor> vals = items.values();
        entity = new GenericEntity<Collection<Actor>>(vals){};
        return Response.ok(entity).build();
    }
}

Why am I still getting this error?

2

2 Answers

0
votes

Yes, Glassfish has Jackson, but it also has MOXy, which is the default provider. MOXy is weird with some types. If you want to disable MOXy so you can use Jackson, you need to set the following property to true

ServerProperties.MOXY_JSON_FEATURE_DISABLE

I haven't used Glassfish in a while, so I am not sure if you will still need to register Jackson, but I'm pretty sure you don't. It should be automatically registered. MOXy basically blocks it from being registered.

0
votes

OK, after some digging, I came up with the following to fix it. @peeskillet was partially right, and this fix is Glassfish specific.

Here is the blog with more context

Here is what fixed it. I needed to implement the following 2 classes:

public class JacksonFeature implements Feature {

    Logger L = LoggerFactory.getLogger(JacksonFeature.class);

    @Override
    public boolean configure(final FeatureContext context) {
        String postfix = "";

        postfix = '.' + context.getConfiguration().getRuntimeType().name().toLowerCase();
        context.property(CommonProperties.MOXY_JSON_FEATURE_DISABLE + postfix, true); 

        L.info("Set property to true disable MOXY: " + CommonProperties.MOXY_JSON_FEATURE_DISABLE + postfix);
        context.register(JsonParseExceptionMapper.class);
        context.register(JsonMappingExceptionMapper.class);
        context.register(JacksonJsonProvider.class, MessageBodyReader.class, MessageBodyWriter.class);
        return true;
    }
}

@javax.ws.rs.ApplicationPath("api")
public classMyResourceConfig extends ResourceConfig {

    publicMyServicesResourceConfig() {
        register( new GZipEncoder() );
        register( JacksonFeature.class );
        addMyResources();
    }

    private void addMyResources() {
        register( Service1.class );
        register( Service2.class );
    }
}