users@jersey.java.net

[Jersey] Re: (De)Serializing Custom MIME types

From: Eric Stein <steine_at_locustec.com>
Date: Fri, 27 Jun 2014 20:51:21 +0000

I chased it down to:
org.glassfish.jersey.message.internal.MessageBodyFactory
    @SuppressWarnings("unchecked")
    private <T> MessageBodyWriter<T> _getMessageBodyWriter(Class<T> c, Type t,
                                                           Annotation[] as,
                                                           MediaType mediaType,
                                                           List<MbwModel> models,
                                                           PropertiesDelegate propertiesDelegate) {

        List<MbwModel> writers = mbwLookupCache.get(new ModelLookupKey(c, mediaType));
        if (writers == null) {

            writers = new ArrayList<MbwModel>();

            for (MbwModel model : models) {
                if (isCompatible(model, c, mediaType)) {
      ...

isCompatible is returning false for the org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider. This is what isCompatible looks like:

org.glassfish.jersey.message.internal.MessageBodyFactory

    @SuppressWarnings("unchecked")
    private <T> boolean isCompatible(WorkerModel<T> model, Class c, MediaType mediaType) {
        if (model.providerClassParam.equals(Object.class) ||
               // looks weird. Could/(should?) be separated to Writer/Reader check
                model.providerClassParam.isAssignableFrom(c) ||
                c.isAssignableFrom(model.providerClassParam)
                ) {
            for (MediaType mt : model.types) {
                if (mediaType == null) {
                    return true;
                }

                if (MediaTypes.typeEqual(mediaType, mt) ||
                        MediaTypes.typeEqual(MediaTypes.getTypeWildCart(mediaType), mt) ||
                        MediaTypes.typeEqual(MediaTypes.GENERAL_MEDIA_TYPE, mt)) {
                    return true;
                }
            }
        }

        return false;
    }

Note that isCompatible is *not* asking the MessageBodyWriter if the media type isWritable(). I'm not really sure why it wouldn't do that. This deferrment to the media type is from 2.4 - 2.8. Presumably this is a bug that should be fixed? Jackson is ready and able to (de)serialize my custom media type, but Jersey isn't letting it.

What is the workaround for this? Do I need to write custom MessageBody(Reader/Writer) instances for all my media types? I thought I read somewhere that they could leverage the existing Jackson implementation somehow. Is there a good web resource which will walk me through doing this?

Thanks,
Eric

From: Eric Stein
Sent: Friday, June 27, 2014 3:24 PM
To: users_at_jersey.java.net
Subject: (De)Serializing Custom MIME types


I read in an old thread that support for custom MIME types should work out of the box:



    Anything "+json" should work out of the box

                - Martin Maula-3

                http://jersey.576304.n2.nabble.com/Application-Specific-content-types-and-JAXB-annotations-td6380235.html



but that hasn't been my experience. I have a resource


    @POST
    @Consumes("application/vnd.locustec.eim.initial.query.v1+json")
    @Produces("application/vnd.locustec.eim.secured.query.v1+json")
    public Response createSecuredQuery(

            @ApiParam(required = true) final InitialQueryBean initialQuery) {



I have a simple bean:

@XmlRootElement(name = "InitialQuery")
public final class InitialQueryBean {

    @JsonProperty("initialQuery")
    public String getInitialQuery() { ...
    public void setInitialQuery(final String initialQuery) { ...

    @JsonProperty("restrictQueryToSites")
    public Set<String> getRestrictQueryToSites() {...
    public void setRestrictQueryToSites(final Set<String> restrictQueryToSites) { ...

}



and a simple test case:
    @Test
    public void testCreateSecuredQuery() {

        final Response response =
                this.target("/secured-queries")
                .request("application/vnd.locustec.eim.secured.query.v1+json")
                .post(Entity.entity(this.initialQueryBean, "application/vnd.locustec.eim.initial.query.v1+json"));



but I'm seeing

org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException:

MessageBodyWriter not found for

media type=application/vnd.locustec.eim.initial.query.v1+json,

type=class com.locustec.eim.query.rest.InitialQueryBean,

genericType=class com.locustec.eim.query.rest.InitialQueryBean.



If I change everything to MediaType.APPLICATION_JSON, it my test runs just fine. So what am I doing wrong here? I'm running Jersey 2.4.