«1. Обзор
В этом кратком руководстве мы проанализируем сортировку сущностей без геттеров и решение для исключения Jackson JsonMappingException.
Если вы хотите копнуть глубже и узнать о других интересных вещах, которые вы можете делать с Jackson 2, — переходите к основному учебнику по Джексону.
2. Проблема
По умолчанию, Jackson 2 будет работать только с полями, которые либо общедоступны, либо имеют общедоступные методы получения — сериализация объекта, у которого все поля закрыты или закрыты для пакета, завершится ошибкой: ~ ~~
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());
}
Полное исключение:
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. Решение
Очевидным решением является добавление геттеров для полей, если сущность находится под нашим контролем. Если это не так и модификация источника сущности невозможна, тогда Джексон предлагает нам несколько альтернатив.
3.1. Глобальное автоматическое определение полей с любой видимостью
Первым решением этой проблемы является глобальная настройка ObjectMapper для обнаружения всех полей, независимо от их видимости:
objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
Это позволит обнаруживать частные поля и поля пакета. без геттеров, и сериализация будет работать корректно:
@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. Обнаружены все поля на уровне класса
Другой вариант, предоставляемый Jackson 2, — вместо глобальной конфигурации — управление видимостью поля на уровне класса с помощью аннотации @JsonAutoDetect:
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class MyDtoNoAccessors { ... }
С помощью этой аннотации , сериализация теперь должна работать правильно с этим конкретным классом:
@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. Заключение
В этой статье показано, как обойти видимость поля по умолчанию в Jackson, настроив пользовательскую видимость либо глобально на ObjectMapper, либо на индивидуальные занятия. Джексон допускает дальнейшую настройку, предоставляя параметры для точного управления тем, как геттеры, сеттеры или поля с определенной видимостью видны картографу.
Реализацию всех этих примеров и фрагментов кода можно найти в моем проекте GitHub — это проект на основе Eclipse, поэтому его легко импортировать и запускать как есть.