Как указать Джексона, чтобы использовать только поля - желательно глобально

Поведение Джексона по умолчанию, кажется, использует как свойства (методы получения и установки), так и поля для сериализации и десериализации в json.

Я хотел бы использовать поля в качестве канонического источника конфигурации сериализации и, следовательно, не хочу, чтобы Джексон смотрел на свойства вообще.

Я могу сделать это на индивидуальной основе класса с аннотацией:

 @JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)

Но я не хочу ставить это на каждый класс...

Можно ли настроить это глобально? Как добавить некоторые в Object Mapper?

9 ответов

Решение

Вы можете настроить отдельные ObjectMappers следующим образом:

ObjectMapper mapper  = new ObjectMapper();
mapper.setVisibilityChecker(mapper.getSerializationConfig().getDefaultVisibilityChecker()
                .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
                .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withCreatorVisibility(JsonAutoDetect.Visibility.NONE));

Если вы хотите, чтобы он был установлен глобально, я обычно обращаюсь к настроенному преобразователю через класс-оболочку.

В Jackson 2.0 и более поздних версиях вы можете просто использовать:

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;   

...

ObjectMapper mapper = new ObjectMapper();    
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);

отключить автоопределение.

Специально для boolean is*() добытчики:

Я провел много времени: почему ни

  @JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE) 

нет

  setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE);
  setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE);
  setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);

не работает для моего логического метода получения / установки. Решение просто:

  @JsonAutoDetect(isGetterVisibility = Visibility.NONE, ...          
  setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE);

Для джексона 1.9.10 использую

ObjectMapper mapper = new ObjectMapper();

mapper.setVisibility(JsonMethod.ALL, Visibility.NONE);
mapper.setVisibility(JsonMethod.FIELD, Visibility.ANY);

к повороту автоопределения.

Как насчет этого: я использовал его с миксином

несоответствующий объект

@Entity
@Getter
@NoArgsConstructor
public class Telemetry {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long pk;
    private String id;
    private String organizationId;
    private String baseType;
    private String name;
    private Double lat;
    private Double lon;
    private Instant updateTimestamp;
}

Mixin:

@JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, setterVisibility = NONE)
public static class TelemetryMixin {}

Использование:

    ObjectMapper om = objectMapper.addMixIn(Telemetry.class, TelemetryMixin.class);
    Telemetry[] telemetries = om.readValue(someJson, Telemetry[].class);

Нет ничего, что говорило бы, что вы не можете учить любое количество классов и применять один и тот же миксин.

Если вы не знакомы с миксинами, они концептуально просты: структура миксина наложена на целевой класс (согласно Джексону, не так, как JVM).

Если вы используете Spring Boot, вы можете настроить Jackson глобально следующим образом:

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

@Configuration
public class JacksonObjectMapperConfiguration implements Jackson2ObjectMapperBuilderCustomizer {

    @Override
    public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
        jacksonObjectMapperBuilder.visibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
        jacksonObjectMapperBuilder.visibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
        jacksonObjectMapperBuilder.visibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.ANY);
    }

}

Если вам нужен способ сделать это глобально, не беспокоясь о конфигурации вашего ObjectMapper, вы можете создать свою аннотацию:

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonAutoDetect(
        getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE,
        setterVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE,
        creatorVisibility = JsonAutoDetect.Visibility.NONE
)
public @interface JsonExplicit {
}

Теперь вам просто нужно аннотировать свои классы с помощью @JsonExplicit и тебе хорошо идти!

Также не забудьте отредактировать приведенный выше вызов на @JsonAutoDetect чтобы убедиться, что у вас установлены значения, которые работают с вашей программой.

Благодарим /questions/47737254/kak-sozdat-annotatsiyu-kotoraya-predstavlyaet-soboj-gruppu-annotatsij-dzheksona/47737275#47737275 за то, что помогли мне узнать о@JacksonAnnotationsInside

@since 2.10версии, мы можем использовать JsonMapper.Builder, и принятый ответ может выглядеть так:

JsonMapper mapper = JsonMapper.builder()
    .visibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
    .visibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE)
    .visibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE)
    .visibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.NONE)
    .build();

В Kotlin очень сложно работать с классами данных и методами is *. Например для класса:

      data class SomeClass(val foo: String, val bar: String, val isSomething: Boolean):Serializable { fun isEmpty() = foo.isEmpty() }

Я получаю json вроде: {"bar"="bar", "empty"=false, "foo"="foo", "isSomething"=true} И после настройки: setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE) json: {"bar"="bar", "foo"="foo"}

Единственный способ, которым я нашел isSomething и нет empty добавляет @JsonIgnore или @JvmSynthetic аннотация на isEmpty()

Более того, интересным фактом является то, что такой метод добавления, как isFoo(): Boolean сериализует foo только один раз в виде String.

Другие вопросы по тегам