【问题标题】:Spring/json: Convert a typed collection like List<MyPojo>Spring/json:转换像 List<MyPojo> 这样的类型化集合
【发布时间】:2011-09-04 14:47:16
【问题描述】:

我正在尝试通过 Spring Rest 模板编组一个列表:List&lt;Pojo&gt; 对象。

我可以传递简单的 Pojo 对象,但我找不到任何描述如何发送 List&lt;Pojo&gt; 对象的文档。

Spring 正在使用 Jackson JSON 来实现 HttpMessageConverter。杰克逊文档涵盖了这一点:

除了绑定到 POJO 和 “简单”类型,有一种 附加变体:绑定到 通用(类型)容器。这个案例 由于需要特殊处理 所谓的类型擦除(Java 使用 在某种程度上实现泛型 向后兼容的方式),其中 阻止您使用类似的东西 Collection&lt;String&gt;.class(确实 不编译)。

所以如果你想将数据绑定到一个 Map&lt;String,User&gt;你需要使用:

Map&lt;String,User&gt; result = mapper.readValue(src, new TypeReference&lt;Map&lt;String,User&gt;&gt;() {});

其中TypeReference 只需要 通过泛型类型定义(通过 在这种情况下是任何内部类): 重要的部分是 &lt;Map&lt;String,User&gt;&gt; 定义类型 绑定到。

这可以在 Spring 模板中完成吗?我看了一眼代码,这让我不以为然,但也许我只是不知道一些技巧。


解决方案

由于以下有用的答案,最终的解决方案是不发送列表,而是发送一个简单地扩展列表的对象,例如:class PojoList extends ArrayList&lt;Pojo&gt;。 Spring 可以成功地编组这个对象,它完成与发送List&lt;Pojo&gt; 相同的事情,尽管它的解决方案不太干净。我还在春季为他们发布了一个 JIRA,以在他们的 HttpMessageConverter 界面中解决这个缺点。

【问题讨论】:

    标签: java spring collections spring-mvc jackson


    【解决方案1】:

    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);
    

    像魅力一样工作!

    【讨论】:

    • 我不明白/不了解您如何使用它来返回 JSON 对象。这不是把那些放在客户端上以确保它正在使用特定类型的请求调用服务器吗?
    • 谢谢它的帮助.. 在你拥有身体后,你需要将它类型转换为所需的类型.. 对于上面的例子,它应该是 ((List)re​​sponse.getBody())
    • @AnoopIsaac 这可能取决于您使用的 Spring 版本。在 Spring 4.0 中,不需要对 body 进行类型转换;它已经是List&lt;MyBean&gt; 的类型,这是首先参数化response 的重点。我打赌这在 Spring 3.2 中可能也是如此。
    【解决方案2】:

    确保包含泛型类型参数的一种方法是实际对 List 或 Map 类型进行子类化,这样您就有了类似的东西:

    static class MyStringList extends ArrayList<String> { }
    

    并返回该列表的实例。

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

    除此之外,您还需要弄清楚如何将 Jackson 传递给 JavaTypeTypeReference 以伴随价值。

    【讨论】:

      【解决方案3】:

      如果我没看错docs for MappingJacksonHttpMessageConverter,您将不得不创建并注册MappingJacksonHttpMessageConverter 的子类并覆盖getJavaType(Class&lt;?&gt;) 方法:

      返回 Jackson JavaType 的 具体类。默认实现 返回 TypeFactory.type(java.lang.reflect.Type), 但这可以被覆盖 子类,以允许自定义 通用集合处理。为了 实例:

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

      【讨论】:

      • 如果我误解了这里的问题,请纠正我,但是传递一个Class来getJavaType需要类型擦除(你不能传递List.class),你只能传递List.class,意思是你无法知道要创建哪种类型的 List (因此您最终只能创建通用 JSON 对象,而不是 List 中所需的 Pojo 对象。我可能不在此处,或者需要重新构建问题以了解但是,请花点时间考虑一下,让我知道您的想法。到目前为止,我的理解是:整个 HttpMessageConverter 接口限制了您创建类型化集合的能力。
      • @David 不,你理解正确,所以你的子类必须以某种方式“知道”Mybean.class 是什么。 (这可以通过命名约定、自定义注释等来实现。)
      【解决方案4】:

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

      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&lt;Pojo&gt; 的最终类。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-01-27
        • 2023-03-15
        • 2016-08-23
        • 2022-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多