Як вказати Джексону, щоб використовувати лише поля - бажано глобально


191

Як правило, поведінка jackon використовує як властивості (getters та setters), так і поля для серіалізації та deserialize до json.

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

Я можу це зробити на індивідуальній основі з анотацією:

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

Але я не хочу ставити це на кожен клас ...

Чи можливо це налаштувати глобально? Подобається додати трохи до Mapper Object?


1
Тім дав добру відповідь. Інша можливість полягає в тому, що якщо у вас є загальний базовий клас, ви можете помістити анотації до цього класу; анотації успадковує Джексон.
StaxMan

1
Я думаю, що я спробував це, але, здається, ви повинні сказати підкласам, щоб використовувати те, що визначає базовий випадок ...
Майкл Вілз

2
Ні, якщо субклас замінює анотацію класу, анотації батьків видно так, як ніби вони були частиною визначення підкласу (якщо ні, це буде помилка). Це не обов'язково, як JDK поводиться з анотаціями, але Джексон реалізує повне успадкування для анотацій (навіть для анотацій методів).
StaxMan

Остерігайтеся INFER_PROPERTY_MUTATORSпрапора. Це примушує видимість сетерів, якщо є видимий геттер або поле.
Ondra Žižka

Відповіді:


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
Добре, хоча я думаю, що вам може знадобитися також встановити шашку (з методамиXXX () зазвичай створюють новий об’єкт). Так щось на зразок 'mapper.setVisibilityChecker (mapper.getVisibilityChecker (). З ...);'
StaxMan

@StaxMan хороший дзвінок на setVisibilityChecker, я відредагував відповідь, щоб відобразити.
Кевін Боуерсокс

42
withGetterVisibilityне охоплює is*методів, але withIsGetterVisibilityдля них є.
qerub

13
setVisibilityCheckerзастаріло. Використовуйте setVisibilityзамість цього.
0x7d7b

1
Це саме те, що мені було потрібно! Ця конфігурація дозволила мені використовувати Mixin, щоб легко перетворити сплячі об'єкти в 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);

щоб вимкнути автоматичне виявлення.


1
Привіт, хлопці, я використовую банку "Джексон 1.9.0". Я отримую додаткове властивість json, при цьому серіалізуючи об’єкт до рядка json. Мені потрібно отримати рядок json, який містить лише згадані змінні з @JsonProperty. Чи можете ви мені допомогти в цьому?
jrhamza

7
Ви можете почати з анотації до класу, згаданої у питанні про ОП: @JsonAutoDetect(fieldVisibility = Visibility.NONE, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)Далі, ви маєте коментувати кожну властивість, яку ви хочете включити@JsonProperty
lukk

Дякую! Раніше я знайшов багато прикладів коду, де на посилання на JsonMethod замість PropertyAccessor. Якщо ви шукаєте 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);

працював на мого булевого геттера / сеттера.

Рішення просте:

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

UPDATE: Spring-boot дозволило налаштувати його:

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

повернути автодедекцію.


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


3

Якщо ви використовуєте 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);
    }

}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.