如何指定Jackson仅使用字段 - 最好是全局的

229

默认的jackson行为似乎同时使用属性(getters和setters)和字段来序列化和反序列化为json。

我希望使用字段作为序列化配置的规范来源,因此不想让jackson查看属性。

我可以使用以下注释在单个类上实现此目的:

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

但我不想在每个类中都加上这个...

有没有可能进行全局配置?比如添加到对象映射器中?


1
Tim 给出了一个好答案。另一个可能性是,如果你有一个共同的基类,你可以把类注释放到那个基类上;注释会被 Jackson 继承。 - StaxMan
1
我想我尝试过了,但似乎你必须告诉子类使用基本情况定义的内容... - Michael Wiles
2
不会,除非子类覆盖了父类的注释,否则父类的注释将作为子类定义的一部分可见(如果没有,则这将是一个错误)。这不一定是 JDK 处理注释的方式,但 Jackson 实现了对注释的完全继承(即使方法注释也是如此)。 - StaxMan
小心 INFER_PROPERTY_MUTATORS 标志。如果有可见的 getter 或 field,它会强制 setter 可见。 - Ondra Žižka
和其他 - Ondra Žižka
9个回答

193
您可以像这样配置独立的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));

如果你想全局设置它,我通常会通过一个包装类访问配置的映射器。


4
不错,虽然我认为您可能还需要设置检查器(通常withXxx()方法会创建一个新对象)。因此需要类似“mapper.setVisibilityChecker(mapper.getVisibilityChecker().with...);”这样的代码。 - StaxMan
@StaxMan 在 setVisibilityChecker 上的建议很好,我已经编辑了答案以反映这一点。 - Kevin Bowersox
56
withGetterVisibility 不包括 is* 方法,但是对于它们有 withIsGetterVisibility - qerub
15
setVisibilityChecker已被弃用,请使用setVisibility代替。 - Henrik Sachse
1
这正是我所需要的!这个配置允许我使用Mixin轻松地将Hibernate实体转换为DTO。默认情况下,ObjectMapper会序列化所有内容,而Mixin则必须指定要忽略哪些属性(即减法而不是交集)。 - TastyWheat
1
@StaxMan 谢谢,这个评论刚刚救了我。 - PowR

182

在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
大家好,我正在使用Jackson 1.9.0 jar。在将对象序列化为JSON字符串时,我会得到额外的JSON属性。我需要获取仅包含带有@JsonProperty注释的变量的JSON字符串。你们能帮我吗? - jrh
8
您可以从OP问题中提到的类注释开始: @JsonAutoDetect(fieldVisibility = Visibility.NONE, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE) 接下来,您需要使用@JsonProperty对要包含的每个属性进行注释。 - lukk
谢谢!之前,我发现很多代码示例中引用了JsonMethod而不是PropertyAccessor。如果你搜索JsonMethod,很少会得到指向PropertyAccessor的链接...那么,在后继的工件中找到替换类名的最佳方法是什么呢?这可能会很困难和棘手,对吧? - philburns

47

特别针对 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);

更新:spring-boot 允许配置它:

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

请查看常用应用属性 # JACKSON


1
你能详细说明如何将简单的解决方案应用到Bean类吗? - Pavel Niedoba
1
谢谢。是 isGetter 为我解决了问题。 - grinch
这不是对问题的回答,而是具有误导性的。 - Ondra Žižka

18

对于Jackson 1.9.10,我使用:

ObjectMapper mapper = new ObjectMapper();

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

关闭自动检测。


2
那就是这样。谢谢。 - cuneytykaya
不知道这样做和禁用“自动检测”有什么区别。 - xenoterracide

10
这样如何:我用一个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;
}

混合(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);

没有任何规定说你不能对任意数量的类进行foreach并应用相同的mixin。

如果您不熟悉mixins,它们在概念上非常简单:mixin的结构被叠加到目标类上(根据jackson的说法,这并不涉及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://dev59.com/72Yr5IYBdhLWcg3wxM-8#13408807帮助我找到有关@JacksonAnnotationsInside的信息。

6
如果您使用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);
    }

}


3

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

1

在 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"}
我找到的唯一方法是在isEmpty()上添加@JsonIgnore@JvmSynthetic注释,以保留isSomething并消除empty
此外,有趣的事实是添加诸如isFoo(): Boolean之类的方法只会将foo序列化一次,作为字符串。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接