Jersey REST Client - Treat Custom MediaType as MediaType.APPLICATION_JSON
Asked Answered
I

1

10

I'm writing a REST client using Jersey with JacksonFeature enabled for a webservice that forces me to specify their custom-named content type, even though it's just regular JSON. In other words, when I do this:

Request request = buildMySampleRequestPojo();

Response response = requestBuilder.post(
        Entity.entity(request, MediaType.APPLICATION_JSON)
);

The service complains that I'm using an invalid content type. I can get around this by specifying their custom-named media type in place of the MediaType.APPLICATION_JSON constant:

Response response = requestBuilder.post(
        Entity.entity(request, "vnd.stupidNameThatReallyIsJustJSON+json")
);

However, when I do that, I get:

*SEVERE: MessageBodyWriter not found for media type=stupidNameThatReallyIsJustJSON*

Is there a way I can have Jersey treat this customized media type name as if it were regular JSON without writing a customized MessageBodyWriter?

Innocency answered 2/6, 2015 at 19:38 Comment(2)
have you tried using the conventional media type format, e.g. application/vnd.stupidNameThatReallyIsJustJSON+json?Aborigine
Yes, in my 2nd code example that's more what the format o the actual media type name looks like I just tried to obfuscate it a littleInnocency
A
8

I think you could use both this (JAX-RS entity providers) and this (use Jackson with Jersey), in order to achieve what you want. In a nutshell, register a MessageBodyWriter annotated with @Produces("application/vnd.stupidNameThatReallyIsJustJSON+json") and in the implementation just delegate the marshalling/unmarshalling to Jackson.

EDIT : try with something along the lines of

package my.pack.age;

import com.sun.jersey.core.provider.AbstractMessageReaderWriterProvider;
import com.sun.jersey.core.util.ReaderWriter;

import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

@Produces("application/vnd.stupidNameThatReallyIsJustJSON+json")
public class MyJsonBodyWriter<T> extends AbstractMessageReaderWriterProvider<T> {

    // T should be your pojo in this case. If you can make your pojo compatible with org.codehaus.jettison.json.JSONObject,
    // then you can extend com.sun.jersey.json.impl.provider.entity.JSONObjectProvider and delegate all the methods of
    // MessageBodyWriter (and MessageBodyReader) to that. Otherwise just implement them.

    @Override
    public T readFrom(Class<T> type, Type genericType, Annotation annotations[], MediaType mediaType,MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException {
        try {
//            deserialize entityStream according to the given media type and return a new instance of T.
//            
//            You can do it like this (just an example) :
//            JSONObject myObject = new JSONObject();
//            try {
//                these names and values should come from the stream.
//                myObject.put("name", "Agamemnon");
//                myObject.put("age", 32);
//            } catch (JSONException ex) {
//                LOGGER.log(Level.SEVERE, "Error ...", ex);
//            }
            return null;
        } catch (Exception e) {
            throw new WebApplicationException(new Exception("Error during deserialization", e),400);
        }
    }

        @Override
    public void writeTo(T t,Class<?> type, Type genericType, Annotation annotations[], MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException {
        try {
            OutputStreamWriter writer = new OutputStreamWriter(entityStream, ReaderWriter.getCharset(mediaType));
            // write t on the writer
            writer.flush();
        } catch (Exception e) {
            throw new WebApplicationException( new Exception("Error during serialization", e), 500);
        }
    }

    @Override
    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        // should return true if this class can serialize the given type to the given media type
        return true;
    }

    @Override
    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        // should return true if this class can deserialize the given type to the given media type
        return true;
    }

    @Override
    public long getSize(T t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        // calculate and return content-lenght, i.e. the lenght of the serialized representation of t
        return 0;
    }

}

Obviously this is just a starting point, not a working example, but it should give you enough information to start. Also remember that you'll have to register the class to Jersey in order to let it use it.

Aborigine answered 3/6, 2015 at 12:28 Comment(3)
haven't forgotten about you franc, just waiting for some free time to come along so i can try this solution.Innocency
Franc could you provide some more detail? What MessageBodyWriter could I use in this case? Would I have to create my own class? Is there an existing "JSONMessageBodyWriter" class I could subclass and just annotate with the @Produces annotation you mentioned?Innocency
@Innocency JacksonJsonProviderGyratory

© 2022 - 2024 — McMap. All rights reserved.