Jersey REST客户端——将自定义MediaType视为MediaType. application_json

时间:2022-11-22 19:33:59

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:

我正在编写一个REST客户端,使用Jersey和JacksonFeature支持一个webservice,它强迫我指定他们定制的内容类型,即使它只是普通的JSON。换句话说,当我这样做的时候

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:

服务抱怨我使用的是无效的内容类型。我可以通过指定自定义命名的媒体类型来替代中介类型来解决这个问题。APPLICATION_JSON不变:

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?

是否有一种方法可以让Jersey在不编写自定义MessageBodyWriter的情况下,将这个自定义媒体类型名称视为常规JSON ?

1 个解决方案

#1


7  

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.

我认为您可以使用这个(JAX-RS实体提供程序)和这个(使用Jackson和Jersey)来实现您想要的。简单地说,注册一个带有@Produces注解的MessageBodyWriter(“application/ vnd.stupidnamethatallyisjustjson +json”),在实现中只将编组/反编组委托给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.

显然,这只是一个起点,而不是一个工作示例,但它应该为您提供足够的信息。还要记住,您必须将类注册到Jersey,以便让它使用它。

#1


7  

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.

我认为您可以使用这个(JAX-RS实体提供程序)和这个(使用Jackson和Jersey)来实现您想要的。简单地说,注册一个带有@Produces注解的MessageBodyWriter(“application/ vnd.stupidnamethatallyisjustjson +json”),在实现中只将编组/反编组委托给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.

显然,这只是一个起点,而不是一个工作示例,但它应该为您提供足够的信息。还要记住,您必须将类注册到Jersey,以便让它使用它。