Jersey REST 客户端 - 将自定义 MediaType 视为 MediaType.APPLICATION_JSON

Posted

技术标签:

【中文标题】Jersey REST 客户端 - 将自定义 MediaType 视为 MediaType.APPLICATION_JSON【英文标题】:Jersey REST Client - Treat Custom MediaType as MediaType.APPLICATION_JSON 【发布时间】:2015-08-16 18:41:09 【问题描述】:

我正在编写一个使用 Jersey 启用 JacksonFeature 的 REST 客户端,用于强制我指定其自定义命名内容类型的 Web 服务,即使它只是常规 JSON。换句话说,当我这样做时:

Request request = buildMySampleRequestPojo();

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

服务抱怨我使用了无效的内容类型。我可以通过指定他们自定义命名的媒体类型来代替 MediaType.APPLICATION_JSON 常量来解决这个问题:

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

但是,当我这样做时,我得到:

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

有没有一种方法可以让 Jersey 将此自定义媒体类型名称视为常规 JSON,而无需编写自定义 MessageBodyWriter?

【问题讨论】:

您是否尝试过使用传统的媒体类型格式,例如application/vnd.stupidNameThatReallyIsJustJSON+json? 是的,在我的第二个代码示例中,实际媒体类型名称的格式更像是我只是想稍微混淆一下 【参考方案1】:

我认为您可以同时使用this (JAX-RS entity providers) 和this (use Jackson with Jersey),以实现您想要的。简而言之,注册一个带有 @Produces("application/vnd.stupidNameThatReallyIsJustJSON+json") 注释的 MessageBodyWriter 并在实现中将编组/解组委派给 Jackson。

编辑:尝试类似

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;
    


显然,这只是一个起点,而不是一个工作示例,但它应该为您提供足够的信息来开始。另请记住,您必须将类注册到 Jersey 才能让它使用它。

【讨论】:

没有忘记你的法郎,只是等待一些空闲时间来尝试这个解决方案。 法郎 你能提供更多细节吗?在这种情况下我可以使用什么 MessageBodyWriter?我必须创建自己的课程吗?是否有一个现有的“JSONMessageBodyWriter”类我可以子类化并使用您提到的@Produces 注释进行注释? @kwikness JacksonJsonProvider

以上是关于Jersey REST 客户端 - 将自定义 MediaType 视为 MediaType.APPLICATION_JSON的主要内容,如果未能解决你的问题,请参考以下文章

列出所有已部署的 REST 端点(spring-boot、jersey)

Jersey REST 服务抛出超时异常

使用jersey客户端消耗spring REST api

Jersey Rest服务类型

REST - Jersey - 提供跨站点访问

通过生成的Jersey REST客户端检索实体列表