«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, поэтому его легко импортировать и запускать как есть.