如何指定杰克逊只使用字段 - 最好是全局

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 作为字符串序列化一次。

【讨论】:

以上是关于如何指定杰克逊只使用字段 - 最好是全局的主要内容,如果未能解决你的问题,请参考以下文章

如何更改杰克逊以检测 POJO 中的所有字段,而不仅仅是公共字段?

使用杰克逊数据绑定跳过嵌套字段?

如何区分空值字段与杰克逊库中的缺失字段

如何使用杰克逊映射器自动识别不同的类型

如果值为空,如何告诉杰克逊在序列化期间忽略一个字段?

杰克逊,反序列化具有私有字段的类和没有注释的 arg-constructor