【问题标题】:Force JAX-RS to serialize my class to a JSON object强制 JAX-RS 将我的类序列化为 JSON 对象
【发布时间】:2015-05-25 17:36:57
【问题描述】:

我有一个类,它是内部列表周围的装饰器。我想在我的 JAX-RS 服务中使用这个类作为 DTO。其代码如下:

@XmlRootElement(name = "movies")
public class MoviesResponse implements List<Movie> {

    @XmlElement(name = "movie")
    protected List<Movie> movies;

    /* tons of delegate methods */

}

我需要同时支持 application/xml 和 application/json。 格式是固定的,必须是这样的

<movies>
 <movie>
  <foo />
 </movie>
 <movie>
  <foo /> 
 </movie>
</movies>

...在 XML 中,并且

{
 "movie": [
 {},{}
 ]
}

...在 JSON 中。 XML 工作得很好,但 JSON 看起来像这样:

[{},{}]

您可能会怀疑,如果我不实现 List 接口,它会生成我需要的格式。所以我猜序列化器很聪明,把它当作 List 来处理,从而把它序列化成一个数组。但我需要将它序列化为一个对象。我怎样才能做到这一点,实现 List 接口?

【问题讨论】:

    标签: java json serialization jax-rs


    【解决方案1】:

    假设 Jackson 是您的序列化程序,您可以将 ObjectMapper 配置为 WRAP_ROOT_VALUE。您可以在ContextResolver 中执行此操作。为了不为所有类型使用相同的配置,您可以使用两个不同的配置ObjectMappers,一个用于列表类,一个用于其余的。例如

    @Provider
    public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
    
        final ObjectMapper listMapper = new ObjectMapper();
        final ObjectMapper defaultMapper = new ObjectMapper();
    
        public ObjectMapperContextResolver() {
            listMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
            listMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
    
            listMapper.registerModule(new JaxbAnnotationModule());
            defaultMapper.registerModule(new JaxbAnnotationModule());
        }
    
        @Override
        public ObjectMapper getContext(Class<?> type) {
            if (type == MovieList.class) {
                return listMapper;
            }
            return defaultMapper;
        }  
    }
    

    用于编组的MessageBodyWriter 将调用getContext 方法,传入它试图编组的类。根据结果​​,即将使用ObjectMapperWRAP_ROOT_VALUE 所做的是将根值包装在一个对象中,名称是 @JsonRootName@XmlRootElement 中的值(假设 JAXB 注释支持已启用 - 请参阅 here

    测试:

    @Path("/movies")
    public class MovieResource {
    
        @GET
        @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
        public Response getMovieList() {
            MovieList list = new MovieList();
            list.add(new Movie("I Origins"));
            list.add(new Movie("Imitation Game"));
            return Response.ok(list).build();
        }
    }
    

    C:\&gt;curl -v -H "Accept:application/json" http://localhost:8080/api/movies
    结果:
    { "movies" : [ { "name" : "I Origins" }, { "name" : "Imitation Game" } ] }

    更新

    所以我注意到您的列表为protected。也许您以后可能想要扩展 MovieList 类。在这种情况下,这个

    if (type == MovieList.class) {
        return listMapper;
    }
    

    机器人是可行的。相反,您需要检查类型 isAssignableFrom

    if (MovieList.class.isAssignableFrom(type)) {
        return listMapper;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-09
      • 2015-02-16
      • 2014-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多