1. Обзор
В этом кратком руководстве мы проанализируем маршаллинг сущностей без геттеров и решение для исключения Jackson JsonMappingException
.
Если вы хотите копнуть глубже и узнать о других интересных вещах, которые вы можете делать с Jackson 2, — перейдите к основному руководству по Jackson .
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, поэтому его легко импортировать и запускать как есть.