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