Jackson - JsonMappingException (nenhum serializador encontrado para a classe)

Jackson - JsonMappingException (nenhum serializador encontrado para a classe)

1. Visão geral

Neste tutorial rápido, analisaremos o empacotamento de entidades sem getters ethe solution for the Jackson JsonMappingException exception.

Se você quiser se aprofundar e aprenderother cool things you can do with the Jackson 2, vá parathe main Jackson tutorial.

Leitura adicional:

Introdução ao Jackson ObjectMapper

O artigo discute a classe ObjectMapper central de Jackson, a serialização e desserialização básicas, bem como a configuração dos dois processos.

Read more

Usando opcional com Jackson

Uma rápida visão geral de como podemos usar o opcional com Jackson.

Read more

Primavera JSON-P com Jackson

O artigo está focado em mostrar como usar o novo suporte JSON-P no Spring 4.1.

Read more

2. O problema

Por padrão, Jackson 2 só funcionará com campos que sejam públicos ou tenham métodos getter públicos -serializing an entity that has all fields private or package private will fail:

public class MyDtoNoAccessors {
    String stringValue;
    int intValue;
    boolean booleanValue;

    public MyDtoNoAccessors() {
        super();
    }

    // no getters
}
@Test(expected = JsonMappingException.class)
public void givenObjectHasNoAccessors_whenSerializing_thenException()
  throws JsonParseException, IOException {
    String dtoAsString = new ObjectMapper().writeValueAsString(new MyDtoNoAccessors());

    assertThat(dtoAsString, notNullValue());
}

Ofull exception é:

com.fasterxml.jackson.databind.JsonMappingException:
No serializer found for class dtos.MyDtoNoAccessors
and no properties discovered to create BeanSerializer
(to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) )

3. A solução

A solução óbvia é adicionar getters para os campos - se a entidade estiver sob nosso controle. Se esse não for o caso emodifying the source of the entity is not possible - então Jackson nos fornece algumas alternativas.

3.1. Detecção globalmente automática de campos com qualquer visibilidade

Uma primeira solução para esse problema é configurar globalmente oObjectMapper para detectar todos os campos, independentemente de sua visibilidade:

objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);

Isso funcionaráallow the private and package private fields to be detected sem getters e a serialização funcionará corretamente:

@Test
public void givenObjectHasNoAccessors_whenSerializingWithAllFieldsDetected_thenNoException()
  throws JsonParseException, IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
    String dtoAsString = objectMapper.writeValueAsString(new MyDtoNoAccessors());

    assertThat(dtoAsString, containsString("intValue"));
    assertThat(dtoAsString, containsString("stringValue"));
    assertThat(dtoAsString, containsString("booleanValue"));
}

3.2. Todos os campos detectados no nível da classe

Outra opção que Jackson 2 oferece é - em vez da configuração global -control the field visibility at the class level por meio da anotação@JsonAutoDetect:

@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class MyDtoNoAccessors { ... }

Com esta anotação, a serialização agora deve funcionar corretamente com esta classe específica:

@Test
public void givenObjectHasNoAccessorsButHasVisibleFields_whenSerializing_thenNoException()
  throws JsonParseException, IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    String dtoAsString = objectMapper.writeValueAsString(new MyDtoNoAccessors());

    assertThat(dtoAsString, containsString("intValue"));
    assertThat(dtoAsString, containsString("stringValue"));
    assertThat(dtoAsString, containsString("booleanValue"));
}

4. Conclusão

Este artigo ilustrou comoget around the default field visibility in Jackson, configurando uma visibilidade personalizada globalmente emObjectMapper ou em classes individuais. Jackson permite ainda mais personalização, fornecendo opções para controlar exatamente como getters, setters ou campos com visibilidades específicas são vistos pelo mapeador.

A implementação de todos esses exemplos e fragmentos de códigocan be found in my github project - este é um projeto baseado no Eclipse, portanto, deve ser fácil de importar e executar como está.