Как указать Джексона, чтобы использовать только поля - желательно глобально
Поведение Джексона по умолчанию, кажется, использует как свойства (методы получения и установки), так и поля для сериализации и десериализации в 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.