Jackson - JsonMappingException (no se encontró ningún serializador para la clase)

1. Información general

En este tutorial rápido, analizaremos la clasificación de entidades sin captadores y la solución para la excepción Jackson JsonMappingException .

Si desea profundizar y aprender otras cosas interesantes que puede hacer con Jackson 2 , diríjase al tutorial principal de Jackson.

2. El problema

De forma predeterminada, Jackson 2 solo funcionará con campos que sean públicos o que tengan un método getter público; la serialización de una entidad que tiene todos los campos privados o el paquete privado fallará :

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

La excepción completa es:

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. La solución

La solución obvia es agregar captadores para los campos, si la entidad está bajo nuestro control. Si ese no es el caso y no es posible modificar la fuente de la entidad , Jackson nos ofrece algunas alternativas.

3.1. Campos de detección automática global con cualquier visibilidad

Una primera solución a este problema es configurar globalmente el ObjectMapper para detectar todos los campos, independientemente de su visibilidad:

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

Esto permitirá que los campos privados y privados del paquete se detecten sin getters, y la serialización funcionará correctamente:

@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. Detectados todos los campos a nivel de clase

Otra opción que ofrece Jackson 2 es, en lugar de la configuración global, controlar la visibilidad del campo a nivel de clase a través de la anotación @JsonAutoDetect :

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

Con esta anotación, la serialización ahora debería funcionar correctamente con esta clase en particular:

@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. Conclusión

Este artículo ilustró cómo sortear la visibilidad de campo predeterminada en Jackson , configurando una visibilidad personalizada, ya sea globalmente en ObjectMapper o en clases individuales. Jackson permite una personalización aún mayor al proporcionar opciones para controlar exactamente cómo el mapeador ve los captadores, definidores o campos con visibilidades específicas.

La implementación de todos estos ejemplos y fragmentos de código se puede encontrar en mi proyecto de GitHub ; este es un proyecto basado en Eclipse, por lo que debería ser fácil de importar y ejecutar tal como está.