Desserializar string como lista de strings

Sep 23 2020

Eu tenho um POJO que contém os seguintes atributos

public class Example {
  @JsonProperty("inputFoo")
  private String foo
  @JsonProperty("inputBar")
  private String bar
  @JsonProperty("inputBaz")
  @JsonDeserialize(using = MyDeserializer.class)
  private Set<String> baz
}

O JSON com o qual estou trabalhando para representar esses dados atualmente representa o atributo baz como uma única string:

{"inputFoo":"a", "inputBar":"b", "inputBaz":"c"}

Estou usando o Jackson ObjectMapper para tentar converter o JSON em meu POJO. Eu sei que a string de baz de entrada do JSON não será mapeada corretamente para o conjunto que estou tentando representá-la, então defini um desserializador personalizado:

public class MyDeserializer extends StdDeserializer<Set<String>> {
   public MyDeserializer(){}

   public MyDeserializer(Class<?> vc) {
      super(vc);
   }

   public Set<String> deserialize(JsonParser p, DeserializationContext cxt) throws IOException, JsonProcessingException {
      String input = p.readValueAs(String.class);
      Set<String> output = new HashSet<>();
      if(input != null) {
         output.add(input);
      }
      return output;
   }
}

Estou recebendo uma IllegalArgumentException que faz referência ao atributo "inputBaz", sobre a qual posso fornecer detalhes. Alguém vê algum problema óbvio com a implementação do meu desserializador? obrigado

Respostas

2 MichałZiober Sep 22 2020 at 23:33

Você não precisa implementar o desserializador personalizado, use o recurso ACCEPT_SINGLE_VALUE_AS_ARRAY . Também funciona para conjuntos:

Recurso que determina se é aceitável coagir valores não-array (em JSON) para trabalhar com tipos de coleção Java (arrays, java.util.Collection) . Se habilitado, os desserializadores de coleção tentarão manipular valores que não sejam de matriz como se eles tivessem "implícito" a matriz JSON. Esse recurso deve ser usado por motivos de compatibilidade / interoperabilidade, para trabalhar com pacotes (como conversores XML-para-JSON) que omitem o array JSON nos casos em que há apenas um único elemento no array. O recurso está desabilitado por padrão.

Veja também:

  • com.fasterxml.jackson.databind.exc.MismatchedInputException: Não é possível desserializar a instância do java.util.ArrayListtoken START_OBJECT
Andreas Sep 22 2020 at 23:44

Substitua os 2 construtores por este construtor sem argumentos:

public MyDeserializer() {
    super(TypeFactory.defaultInstance().constructCollectionType(Set.class, String.class));
}
pirho Sep 23 2020 at 02:00

ACCEPT_SINGLE_VALUE_AS_ARRAY como sugerido é uma boa opção.

Talvez o seu problema real seja mais complicado, mas se não, você também pode tentar em @JsonCreatorvez do desserializador personalizado. Gostar:

public class Example {

    @JsonCreator
    public Example(@JsonProperty("inputFoo") String foo,
            @JsonProperty("inputBar") String bar,
            @JsonProperty("inputBaz") String strBaz) {
        this.foo = foo;
        this.bar = bar;
        this.baz = new HashSet<>();
        baz.add(strBaz);
    }

    private String foo;
    private String bar;
    private Set<String> baz;
}

Apenas para mostrar que, em casos mais gerais, você pode evitar a implementação do desserializador personalizado com @JsonCreatortambém, mas ainda assim fazer algumas conversões simples.