Автор оригинала: Eugen Paraschiv.
1. Обзор
В этой статье мы рассмотрим различные способы управления , если поле сериализовано/десериализовано Джексоном или нет.
2. Публичное Поле
Самый простой способ убедиться, что поле является сериализуемым и десериализуемым, – это сделать его общедоступным.
Давайте объявим простой класс с открытым, пакет-частным и частным
public class MyDtoAccessLevel { private String stringValue; int intValue; protected float floatValue; public boolean booleanValue; // NO setters or getters }
Из четырех полей класса только public booleanValue по умолчанию будет сериализовано в JSON:
@Test public void givenDifferentAccessLevels_whenPublic_thenSerializable() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); MyDtoAccessLevel dtoObject = new MyDtoAccessLevel(); String dtoAsString = mapper.writeValueAsString(dtoObject); assertThat(dtoAsString, not(containsString("stringValue"))); assertThat(dtoAsString, not(containsString("intValue"))); assertThat(dtoAsString, not(containsString("floatValue"))); assertThat(dtoAsString, containsString("booleanValue")); }
3. Геттер Делает Непубличное поле Сериализуемым и Десериализуемым
Теперь еще один простой способ сделать поле – особенно непубличное поле – сериализуемым – это добавить для него геттер:
public class MyDtoWithGetter { private String stringValue; private int intValue; public String getStringValue() { return stringValue; } }
Теперь мы ожидаем, что поле string Value будет сериализуемым, а другое частное поле-нет, так как у него нет геттера:
@Test public void givenDifferentAccessLevels_whenGetterAdded_thenSerializable() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); MyDtoGetter dtoObject = new MyDtoGetter(); String dtoAsString = mapper.writeValueAsString(dtoObject); assertThat(dtoAsString, containsString("stringValue")); assertThat(dtoAsString, not(containsString("intValue"))); }
Неосознанно геттер также делает частное поле десериализуемым – потому что, как только у него есть геттер, поле считается свойством.
Давайте посмотрим, как это работает:
@Test public void givenDifferentAccessLevels_whenGetterAdded_thenDeserializable() throws JsonProcessingException, JsonMappingException, IOException { String jsonAsString = "{\"stringValue\":\"dtoString\"}"; ObjectMapper mapper = new ObjectMapper(); MyDtoWithGetter dtoObject = mapper.readValue(jsonAsString, MyDtoWithGetter.class); assertThat(dtoObject.getStringValue(), equalTo("dtoString")); }
4. Сеттер Делает Непубличное поле Десериализуемым Только
Мы видели, как геттер сделал частное поле сериализуемым и десериализуемым. С другой стороны, сеттер будет отмечать только непубличное поле как десериализуемое:
public class MyDtoWithSetter { private int intValue; public void setIntValue(int intValue) { this.intValue = intValue; } public int accessIntValue() { return intValue; } }
Как вы можете видеть, в поле private int Value на этот раз есть только сеттер. У нас есть способ получить доступ к значению, но это не стандартный геттер.
Процесс разархивирования для intValue должен работать правильно:
@Test public void givenDifferentAccessLevels_whenSetterAdded_thenDeserializable() throws JsonProcessingException, JsonMappingException, IOException { String jsonAsString = "{\"intValue\":1}"; ObjectMapper mapper = new ObjectMapper(); MyDtoSetter dtoObject = mapper.readValue(jsonAsString, MyDtoSetter.class); assertThat(dtoObject.anotherGetIntValue(), equalTo(1)); }
И, как мы уже упоминали, сеттер должен только сделать поле десериализуемым, но не сериализуемым:
@Test public void givenDifferentAccessLevels_whenSetterAdded_thenStillNotSerializable() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); MyDtoSetter dtoObject = new MyDtoSetter(); String dtoAsString = mapper.writeValueAsString(dtoObject); assertThat(dtoAsString, not(containsString("intValue"))); }
5. Сделайте Все Поля Глобально Сериализуемыми
В некоторых случаях, когда, например, вы на самом деле не сможете напрямую изменить исходный код, нам нужно настроить способ работы Джексона с непубличными полями извне.
Такую глобальную конфигурацию можно выполнить на уровне ObjectMapper, включив функцию AutoDetect для использования методов public fields или getter/setter для сериализации или, возможно, включив сериализацию для всех полей:
ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE); mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
В следующем тестовом примере проверяется, что все поля-члены (включая непубличные) MyDtoAccessLevel сериализуемы:
@Test public void givenDifferentAccessLevels_whenSetVisibility_thenSerializable() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY); MyDtoAccessLevel dtoObject = new MyDtoAccessLevel(); String dtoAsString = mapper.writeValueAsString(dtoObject); assertThat(dtoAsString, containsString("stringValue")); assertThat(dtoAsString, containsString("intValue")); assertThat(dtoAsString, containsString("booleanValue")); }
6. Измените Имя свойства при сериализации/десериализации
Выходя за рамки контроля того, какое поле сериализуется или десериализуется, вы также можете контролировать способ отображения полей в JSON и обратно . Я рассмотрел эту конфигурацию здесь .
7. Игнорируйте поле при сериализации или десериализации
После этого урока у нас есть руководство о том , как полностью игнорировать поле при сериализации и десериализации.
Однако иногда нам нужно игнорировать поле только на одном из них, но не на обоих. Джексон достаточно гибок, чтобы приспособить и этот интересный вариант использования.
В следующем примере показан объект User , содержащий конфиденциальную информацию о пароле, которая не должна быть сериализована в JSON.
Чтобы попасть туда, мы просто добавляем аннотацию @JsonIgnore в геттер пароля и включаем десериализацию поля , применяя аннотацию @JsonProperty к сеттеру:
@JsonIgnore public String getPassword() { return password; } @JsonProperty public void setPassword(String password) { this.password = password; }
Теперь информация о пароле не будет сериализована в JSON:
@Test public void givenFieldTypeIsIgnoredOnlyAtSerialization_whenUserIsSerialized_thenIgnored() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); User userObject = new User(); userObject.setPassword("thePassword"); String userAsString = mapper.writeValueAsString(userObject); assertThat(userAsString, not(containsString("password"))); assertThat(userAsString, not(containsString("thePassword"))); }
Однако JSON, содержащий пароль, будет успешно десериализован в объект User :
@Test public void givenFieldTypeIsIgnoredOnlyAtSerialization_whenUserIsDeserialized_thenCorrect() throws JsonParseException, JsonMappingException, IOException { String jsonAsString = "{\"password\":\"thePassword\"}"; ObjectMapper mapper = new ObjectMapper(); User userObject = mapper.readValue(jsonAsString, User.class); assertThat(userObject.getPassword(), equalTo("thePassword")); }
8. Заключение
В этом уроке рассказывается о том, как Джексон выбирает , какое поле сериализуется/десериализуется, а какое игнорируется в процессе, и, конечно, как получить полный контроль над ним.
Вы также можете перейти к следующему шагу в понимании Jackson 2 , углубившись в такие статьи, как игнорирование поля, десериализация массива JSON в массив или коллекцию Java .
Реализацию всех этих примеров и фрагментов кода можно найти в my github project – это проект на основе Eclipse, поэтому его должно быть легко импортировать и запускать как есть.