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

192

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

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

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

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

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

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

Майкл Уайлс
источник
1
Тим дал хороший ответ. Другая возможность состоит в том, что если у вас есть общий базовый класс, вы можете поместить аннотации к нему; аннотации наследуются Джексоном.
StaxMan
1
Я думаю, что попробовал это, но, похоже, вы должны сказать подклассам использовать то, что определяет базовый вариант ...
Майкл Уайлс
2
Нет, если подкласс не переопределяет аннотацию класса, аннотации родителя видны так, как если бы они были частью определения подкласса (в противном случае это было бы ошибкой). Это не обязательно, как JDK работает с аннотациями, но Джексон реализует полное наследование для аннотаций (даже для аннотаций методов).
StaxMan
Остерегайтесь INFER_PROPERTY_MUTATORSфлага. Это заставляет видимость сеттеров, если есть видимый геттер или поле.
Ондра Жижка
И другие .
Ондра Жижка

Ответы:

157

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

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

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

Тим Хельмштедт
источник
3
Хорошо, хотя я думаю, что вам также может понадобиться установить средство проверки (методы xX () обычно создают новый объект). Так что-то вроде 'mapper.setVisibilityChecker (mapper.getVisibilityChecker (). With ...);'
StaxMan
@StaxMan хороший вызов на setVisibilityChecker, я отредактировал ответ, чтобы отразить.
Кевин Бауэрсокс
42
withGetterVisibilityне охватывает is*методы, но есть withIsGetterVisibilityдля них.
Qerub
13
setVisibilityCheckerустарела. Используйте setVisibilityвместо этого.
0x7d7b
1
Это как раз то, что мне нужно! Эта конфигурация позволила мне использовать Mixin для простого преобразования объектов Hibernate в DTO. По умолчанию ObjectMapper сериализует все, и Mixin должен был бы указать, какие свойства игнорировать (т. Е. Вычитание вместо пересечения).
TastyWheat
150

В 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);

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

Lukk
источник
1
Привет, ребята, я использую Джексон 1.9.0 банку. Я получаю дополнительное свойство json при сериализации объекта в строку json. Мне нужно получить строку json, которая содержит только упомянутые переменные с @JsonProperty. Можете ли вы помочь мне в этом?
Джрхамза
7
Вы можете начать с аннотации класса, упомянутой в вопросе OP: @JsonAutoDetect(fieldVisibility = Visibility.NONE, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)Далее вам нужно аннотировать каждое свойство, с которым вы хотите включить@JsonProperty
lukk
Спасибо! Раньше я нашел много примеров кода, где вместо PropertyAccessor ссылался на JsonMethod. Если вы ищете JsonMethod, вы редко получаете ссылки на PropertyAccessor, а затем ... Каков наилучший способ найти имена замещающих классов в артефактах-преемниках? Может быть жестким и противным, нет?
Филбурн
38

Специально для 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);

работал для моего Boolean Getter / Setter.

Решение простое:

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

ОБНОВЛЕНИЕ: весенняя загрузка позволила настроить это:

jackson:
  visibility.field: any
  visibility.getter: none
  visibility.setter: none
  visibility.is-getter: none

См. Общие свойства приложения # JACKSON

Григорий Кислин
источник
1
Не могли бы вы рассказать, как простое решение должно применяться к классу бобов?
Павел Недоба
1
Спасибо. То есть Геттер спас мне день.
Гринч
Это не ответ на вопрос, а вводит в заблуждение.
Ондра Жижка
14

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

ObjectMapper mapper = new ObjectMapper();

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

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

MFE
источник
2
Это путь. Спасибо.
cuneytykaya
Интересно, есть ли какая-либо разница между выполнением этого и отключением «автоопределения».
ксенотеррацид
10

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

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

@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).

Кристиан Бонджорно
источник
3

Если вы хотите сделать это глобально, не беспокоясь о своей конфигурации 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убедиться, что у вас установлены значения, которые работают с вашей программой.

Благодарим https://stackoverflow.com/a/13408807 за помощь в выяснении@JacksonAnnotationsInside

retodaredevil
источник
3

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

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);
    }

}
раз
источник