Spring boot Jackson Json Serialization for List 实现类(PagedList)

Posted

技术标签:

【中文标题】Spring boot Jackson Json Serialization for List 实现类(PagedList)【英文标题】:Spring boot Jackson Json Serialization for List implementation class (PagedList) 【发布时间】:2016-09-18 18:32:16 【问题描述】:

有没有办法为具有自定义属性的列表实现类添加序列化?

我正在使用 Spring-boot 1.3 开发 Rest 服务。我必须以 Paged-ListNormal-List 的形式返回 JSON 响应,具体取决于 Controller 上的请求。所以,我必须将控制器方法的返回类型保持为通用public List<Employee> getEmployees(int departmentId)

我正在实现如下列表(使用泛型用于不同的对象列表)

public class PagedList<E> implements List<E>  
  private List<E> list;
  private long totalRecords; //Getter-setters are added

  public PagedList(List<E> list) 
    super();
    this.list = list;
  

  public PagedList(List<E> list, long totalRecords) 
    super();
    this.list = list;
    this.totalRecords = totalRecords;
  

  @Override
  public boolean add(E element) 
     return this.list.add(element);
  
  //All other List abstract methods implemented same as above using this.list

为相同添加了JsonSerializer:public class PagedListSerializer extends JsonSerializer&lt;PagedList&gt;serialize() 方法中的序列化逻辑。使用spring-boot jackson customization注册:

@Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() 
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.serializerByType(PagedList.class, new PagedListSerializer());
    return builder;

当我尝试return PagedList&lt;Employee&gt;(list, 1000) 时,我无法得到以下回复。它的返回与普通列表相同。不执行自定义序列化。如何获得以下分页响应?

 
  list : [employeeId: "1", name: "John" , ... ],
  totalRecords : 1000

【问题讨论】:

【参考方案1】:

您可能不需要自定义反序列化器来获取此 json。只需在您的课程中添加 @JsonFormat(shape = JsonFormat.Shape.OBJECT) 注释即可:

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public static class PagedList<E> implements List<E>  
    @JsonProperty
    private List<E> list;

    @JsonProperty // no need for this if you have getter-setters 
    private long totalRecords; 

    @JsonIgnore
    @Override
    public boolean isEmpty() 
        return false;
    

...

这里是完整的演示:https://gist.github.com/varren/35c4ede769499b1290f98e39a2f85589

cmets 后更新:

我认为 Spring 使用 Jacksons return mapper.writerFor(List.class).writeValueAsString(new MyList()); 这是演示:

@RestController
@RequestMapping(value="/")
public static class MyRestController  
    private static final ObjectMapper mapper = new ObjectMapper();

    //returns [] for both 0 and 1
    @RequestMapping(value="test", method = RequestMethod.GET)
    public List test(@RequestParam int user) 
        return user == 0 ? new ArrayList(): new MyList();
    

    //returns [] for 0 and expected custom "empty": true for 1
    @RequestMapping(value="testObj", method = RequestMethod.GET)
    public Object testObj(@RequestParam int user) 
        return user == 0 ? new ArrayList(): new MyList();
    

    // returns expected custom "empty": true
    @RequestMapping(value="testMyList", method = RequestMethod.GET)
    public MyList testMyList() 
        return new MyList();
    

    // returns expected custom "empty": true
    @RequestMapping(value="testMyListMapper", method = RequestMethod.GET)
    public String testMyListMapper() throws JsonProcessingException 
        return mapper.writeValueAsString(new MyList());
    

    // returns []
    @RequestMapping(value="testMyListMapperListWriter", method = RequestMethod.GET)
    public String testMyListMapperListWriter() throws JsonProcessingException 
        return mapper.writerFor(List.class).writeValueAsString(new MyList());
    

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public static class MyList extends ArrayList 

所以您必须选项 1)返回 Object 而不是 List选项 2)为 List 注册自定义序列化程序(而不是 PageList)builder.serializerByType(List.class, new PagedListSerializer()); 像这样:

public class PagedListSerializer extends JsonSerializer<List> 
  @Override
  public void serialize(List valueObj, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException 
    if (valueObj instanceof PagedList) 
      PagedList value = (PagedList) valueObj;
      gen.writeStartObject();
      gen.writeNumberField("totalRecords", value.getTotalRecords());
      gen.writeObjectField("list", value.getList());
      gen.writeEndObject();
    else
      gen.writeStartArray();
      for(Object obj : valueObj)
        gen.writeObject(obj);
      gen.writeEndArray();
    
  

【讨论】:

我尝试使用@JsonFormat(shape = JsonFormat.Shape.OBJECT)@JsonProperty。但它不适用于 Spring 的 rest 服务。 ObjectMapper 没有使用 writeValueAsString() 方法。这是我的源代码供参考 - Spring-boot-jdbc-template @GovindSomani 很棒的演示。您遇到的问题是您使用 List 而不是 PagedList 作为控制器方法的返回类型。 Jackson 甚至没有在寻找 PageList 反序列化器。更改返回类型对您的反序列化器和我的注释都有效i.gyazo.com/0eccca36d668430be083cb2fe733a207.png 是的,你是对的。取决于您的 方法返回类型,它会根据对象配置进行序列化。但我必须保持方法类型通用,在此作为List。正如实际问题中提到的,我也必须以正常列表的形式返回,这取决于相同 api 请求 的请求参数。所以,我不能每次都以PagedList&lt;E&gt; 的身份返回。 eg 中的新 dao 文件 @GovindSomani 更新了我的帖子。我认为您将不得不注册列表序列化程序而不是PagedList,但老实说,这有点奇怪。在客户端将很难解析这个 json。客户端将不得不期待来自服务器的对象 OR 数组,并且使用某些库进行设置可能会很痛苦。 @GovindSomani 顺便说一句,Jackson 通常可以很好地理解对象类型,但我认为其中涉及一些弹簧包装器对象或列表序列化的一些错误,它弄乱了响应 实际上我认为除了在控制器中返回 Object 之外不需要更改任何内容 i.gyazo.com/9837906d67fd1d994ae61061dc1cb689.png【参考方案2】:

您可以创建您的 customObject Mapper 并在那里使用您的序列化程序。

  <mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="custom.CustomObjectMapper"/>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

【讨论】:

我们可以将 ObjectMapper 定义为 bean 来覆盖默认值。您能否提供更多详细信息来编写自定义序列化?这是我的源代码供参考-Spring-boot-jdbc-template @GovindS 您是否能够为对象列表实现自定义序列化。我也在尝试做同样的事情,但自定义序列化程序没有被执行。 @Monisha,是的。您可以参考 [this|***.com/a/37367400/6108027] 答案以供参考。是否使用相同的配置?

以上是关于Spring boot Jackson Json Serialization for List 实现类(PagedList)的主要内容,如果未能解决你的问题,请参考以下文章

尝试通过 Spring Boot Rest 使用 Jackson 验证 JSON

Spring Boot (Jackson):如何避免类名被序列化为 JSON

Spring Boot—08Jackson处理JSON

Spring MVC 接收的 JSON 嵌套对象的 Spring Boot JACKSON 配置

Spring Boot的Jackson JSON映射器[关闭]

在 Jackson / Spring Boot 中测试自定义 Json Deserializer