如何指定杰克逊只使用字段 - 最好是全局
Posted
技术标签:
【中文标题】如何指定杰克逊只使用字段 - 最好是全局【英文标题】:How to specify jackson to only use fields - preferably globally 【发布时间】:2021-09-30 10:56:54 【问题描述】:默认的 jackon 行为似乎同时使用属性(getter 和 setter)和字段来序列化和反序列化为 json。
我想将这些字段用作序列化配置的规范来源,因此根本不希望杰克逊查看属性。
我可以使用注释在单个班级的基础上做到这一点:
@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
但我不想把它放在每个班级...
是否可以全局配置?喜欢在对象映射器中添加一些?
【问题讨论】:
蒂姆给出了一个很好的答案。另一种可能性是,如果您有一个公共基类,您可以将类注释放在那个基类上;注释由 Jackson 继承。 我想我试过了,但似乎你必须告诉子类使用基本案例定义的内容...... 不,除非子类覆盖类注释,否则父类的注释是可见的,就好像它们是子类定义的一部分一样(如果不是,这将是一个错误)。这不一定是 JDK 处理注解的方式,但 Jackson 实现了注解的完全继承(甚至是方法注解)。 当心INFER_PROPERTY_MUTATORS
标志。如果有可见的 getter 或字段,它会强制设置器的可见性。
And others.
【参考方案1】:
您可以像这样配置单个 ObjectMapper:
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));
如果要全局设置,我通常通过包装类访问配置的映射器。
【讨论】:
很好,尽管我认为您可能还需要设置检查器(withXxx() 方法通常会创建一个新对象)。所以像'mapper.setVisibilityChecker(mapper.getVisibilityChecker().with...);'withGetterVisibility
没有涵盖is*
方法,但有withIsGetterVisibility
供他们使用。
setVisibilityChecker
已弃用。请改用setVisibility
。
这正是我所需要的!这种配置允许我使用 Mixin 轻松地将 Hibernate 实体转换为 DTO。默认情况下,ObjectMapper 会序列化所有内容,而 Mixin 必须指定要忽略的属性(即减法而不是交集)。
@StaxMan 谢谢,这条评论救了我。【参考方案2】:
在 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);
关闭自动检测。
【讨论】:
大家好,我使用的是 Jackson 1.9.0 jar。我得到了额外的 json 属性,同时将对象序列化为 json 字符串。我需要获取 json 字符串,它只包含 @JsonProperty 提到的变量。你能帮我解决这个问题吗? 您可以从 OP 问题中提到的类注释开始:@JsonAutoDetect(fieldVisibility = Visibility.NONE, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
接下来,您必须使用 @JsonProperty
注释要包含的每个属性
谢谢!之前,我发现很多代码示例都引用了 JsonMethod 而不是 PropertyAccessor。如果您搜索 JsonMethod,那么您很少会获得指向 PropertyAccessor 的链接......在后续工件中查找替换类名称的最佳方法是什么?可能是强硬和讨厌的,不是吗?【参考方案3】:
专门针对boolean is*()
getter:
我花了很多时间来解释为什么没有低于
@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);
更新:spring-boot 允许配置它:
jackson:
visibility.field: any
visibility.getter: none
visibility.setter: none
visibility.is-getter: none
见Common application properties # JACKSON
【讨论】:
您能否详细说明如何将简单的解决方案应用于 bean 类? 谢谢。那就是Getter为我节省了一天。 这不是问题的答案,而是具有误导性。【参考方案4】:杰克逊 1.9.10 我使用
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(JsonMethod.ALL, Visibility.NONE);
mapper.setVisibility(JsonMethod.FIELD, Visibility.ANY);
关闭自动检测。
【讨论】:
就是这样。谢谢。 想知道这样做和禁用“自动检测”之间是否有任何区别。【参考方案5】:这个怎么样:我用的是 mixin
不合规对象
@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;
混音:
@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);
没有什么说你不能 foreach 任意数量的类并应用相同的 mixin。
如果您不熟悉 mixin,它们在概念上很简单:mixin 的结构是超级强加在目标类上的(根据杰克逊的说法,就 JVM 而言不是) .
【讨论】:
【参考方案6】:如果您想在全局范围内执行此操作而无需担心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://***.com/a/13408807 帮助我了解@JacksonAnnotationsInside
【讨论】:
【参考方案7】:如果你使用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);
【讨论】:
【参考方案8】:@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();
【讨论】:
【参考方案9】:在 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
的唯一方法是在isEmpty()
上添加@JsonIgnore
或@JvmSynthetic
注释
此外,有趣的事实是,像 isFoo(): Boolean
这样的添加方法只会将 foo 作为字符串序列化一次。
【讨论】:
以上是关于如何指定杰克逊只使用字段 - 最好是全局的主要内容,如果未能解决你的问题,请参考以下文章