【问题标题】:Spring boot Jackson Json Serialization for List implementation class (PagedList)Spring boot Jackson Json Serialization for List 实现类(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
}

为相同添加了JsonSerializerpublic 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
}

【问题讨论】:

    标签: json spring-mvc serialization spring-boot jackson


    【解决方案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|stackoverflow.com/a/37367400/6108027] 答案以供参考。是否使用相同的配置?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-02
    • 2016-09-08
    • 2018-11-07
    • 2019-01-13
    相关资源
    最近更新 更多