有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

JavaSpring/json:转换一个类型化的集合,如List<MyPojo>

我试图通过SpringREST模板封送一个列表:List<Pojo>对象

我可以传递简单的Pojo对象,但找不到任何描述如何发送List<Pojo>对象的文档

Spring正在使用Jackson JSON实现HttpMessageConverter。jackson文档包括以下内容:

In addition to binding to POJOs and "simple" types, there is one additional variant: that of binding to generic (typed) containers. This case requires special handling due to so-called Type Erasure (used by Java to implement generics in somewhat backwards compatible way), which prevents you from using something like Collection<String>.class (which does not compile).

So if you want to bind data into a Map<String,User> you will need to use:

Map<String,User> result = mapper.readValue(src, new TypeReference<Map<String,User>>() {});

where TypeReference is only needed to pass generic type definition (via anynomous inner class in this case): the important part is <Map<String,User>> which defines type to bind to.

这可以在Spring模板中完成吗?我瞥了一眼代码,它让我感觉不到什么,但也许我只是不知道一些技巧


解决方案

得益于下面的有用答案,最终的解决方案是不发送列表,而是发送一个简单扩展列表的对象,例如:class PojoList extends ArrayList<Pojo>。Spring可以成功地封送这个对象,它完成了与发送List<Pojo>相同的任务,尽管它的解决方案不太干净。我还在春季为他们发布了一个JIRA,以解决他们HttpMessageConverter接口中的这一缺陷


共 (4) 个答案

  1. # 1 楼答案

    我通过使用以下配置解决了这个问题:

    private static final String POJO_ARRAY_LIST = PojoArrayList.class.getCanonicalName();
    
    @Bean
    public HttpMessageConverter<Object> httpMessageConverter() {
        HttpMessageConverter<Object> httpMessageConverter = new MappingJackson2HttpMessageConverter() {
            @Override
            protected JavaType getJavaType(Type type, @Nullable Class<?> contextClass) {
                JavaType javaType;
                if (type != null && POJO_ARRAY_LIST.equals(type.getTypeName())) {
                    ObjectMapper objectMapper = new ObjectMapper();
                    TypeFactory typeFactory = objectMapper.getTypeFactory();
                    CollectionType collectionType = typeFactory.constructCollectionType(ArrayList.class, Pojo.class);
                    javaType = collectionType;
                } else {
                    javaType = super.getJavaType(type, contextClass);
                }
                return javaType;
            }
        };
        return httpMessageConverter;
    }
    

    其中PojoArrayList是扩展ArrayList<Pojo>的最后一个类

  2. # 2 楼答案

    Spring 3.2中,现在使用RestTemplate上的新exchange()-方法支持泛型类型:

     ParameterizedTypeReference<List<MyBean>> typeRef = new ParameterizedTypeReference<List<MyBean>>() {};
     ResponseEntity<List<MyBean>> response = template.exchange("http://example.com", HttpMethod.GET, null, typeRef);
    

    很有魅力

  3. # 3 楼答案

    如果我正确阅读了docs for ^{},您必须创建并注册MappingJacksonHttpMessageConverter的子类,并重写^{}方法:

    Returns the Jackson JavaType for the specific class. Default implementation returns TypeFactory.type(java.lang.reflect.Type), but this can be overridden in subclasses, to allow for custom generic collection handling. For instance:

    protected JavaType getJavaType(Class<?> clazz) {
       if (List.class.isAssignableFrom(clazz)) {
         return TypeFactory.collectionType(ArrayList.class, MyBean.class);
       } else {
         return super.getJavaType(clazz);
       }
    }
    
  4. # 4 楼答案

    确保包含泛型类型参数的一种方法是实际创建子类列表或映射类型,例如:

    static class MyStringList extends ArrayList<String> { }
    

    并返回该列表的实例

    那么,为什么这会带来不同呢?因为泛型类型信息只保留在几个地方:方法和字段声明,以及超类型声明。所以,虽然“raw”列表不包含任何运行时类型信息,“MyStringList”的类定义通过其超类型声明包含这些信息。 请注意,对看似类型化的变量的赋值并没有帮助:它只会创建更多编译时语法糖:真正的类型信息只通过类实例传递(或由lib提供的扩展,如JavaType和TypeReference)

    除此之外,您还需要弄清楚如何通过JavaTypeTypeReference传递Jackson来伴随值