2 votes

Spring boot Jackson Serialization pour la classe d'implémentation de la liste (PagedList)

Existe-t-il un moyen d'ajouter la sérialisation pour une classe d'implémentation de liste ayant des attributs personnalisés ?

Je travaille sur un service Rest en utilisant Spring-boot 1.3. Je dois retourner une réponse JSON sous la forme Liste paginée o Liste normale Selon la demande du contrôleur. Je dois donc conserver le type de retour de la méthode du contrôleur comme générique public List<Employee> getEmployees(int departmentId)

J'implémente la liste comme suit (en utilisant des génériques pour les différentes listes d'objets)

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
}

Ajouté JsonSerializer pour les mêmes : public class PagedListSerializer extends JsonSerializer<PagedList> avec une logique de sérialisation dans serialize() méthode. Celle-ci est enregistrée à l'aide de spring-boot jackson customisation :

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

Lorsque j'essaie de return PagedList<Employee>(list, 1000) Je ne parviens pas à obtenir la réponse suivante. La réponse est la même que celle d'une liste normale. La sérialisation personnalisée n'est pas exécutée. Comment obtenir la réponse paginée suivante ?

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

1voto

varren Points 4621

Vous n'avez probablement pas besoin d'un désérialiseur personnalisé pour obtenir ce json. Ajoutez simplement @JsonFormat(shape = JsonFormat.Shape.OBJECT) à votre classe :

@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;
    }

...

Voici la démo complète : https://gist.github.com/varren/35c4ede769499b1290f98e39a2f85589

Mise à jour après les commentaires :

Je pense que Spring utilise Jacksons return mapper.writerFor(List.class).writeValueAsString(new MyList()); Voici la démo :

@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 {}

Vous devez donc Option 1 ) retour Object au lieu de List o Option 2 ) enregistrer un sérif personnalisé pour Liste (et non pour PageList) builder.serializerByType(List.class, new PagedListSerializer()); comme ceci :

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

0voto

Vous pouvez créer votre mappeur d'objets personnalisé et y utiliser votre sérialiseur.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X