Jackson 序列化:如何忽略超类属性
Posted
技术标签:
【中文标题】Jackson 序列化:如何忽略超类属性【英文标题】:Jackson serialization: how to ignore superclass properties 【发布时间】:2015-01-12 18:21:06 【问题描述】:我想序列化一个不受我控制的 POJO 类,但想避免序列化来自超类而不是最终类的任何属性。示例:
public class MyGeneratedRecord extends org.jooq.impl.UpdatableRecordImpl<...>,
example.generated.tables.interfaces.IMyGenerated
public void setField1(...);
public Integer getField1();
public void setField2(...);
public Integer getField2();
...
从例子中你可以猜到这个类是由JOOQ生成的,继承自一个复杂的基类UpdatableRecordImpl,它也有一些类似bean属性的方法,这会导致序列化过程中出现问题。另外,我有几个类似的类,所以最好避免为我生成的所有 POJO 重复相同的解决方案。
到目前为止,我已经找到了以下可能的解决方案:
使用 mixin 技术忽略来自超类的特定字段,如下所示:How can I tell jackson to ignore a property for which I don't have control over the source code?
这样做的问题是,如果基类发生变化(例如,其中出现了一个新的 getAnything() 方法),它可能会破坏我的实现。
实现自定义序列化程序并在那里处理问题。这对我来说似乎有点矫枉过正。
顺便说一句,我有一个接口,它准确描述了我想要序列化的属性,也许我可以混合一个 @JsonSerialize(as=IMyGenerated.class) 注释......?我可以将其用于我的目的吗?
但是,从纯设计的角度来看,最好的办法是能够告诉杰克逊我只想序列化最终类的属性,而忽略所有继承的属性。有没有办法做到这一点?
提前致谢。
【问题讨论】:
【参考方案1】:您可以注册一个自定义Jackson annotation intropector,它将忽略来自某个超类型的所有属性。这是一个例子:
public class JacksonIgnoreInherited
public static class Base
public final String field1;
public Base(final String field1)
this.field1 = field1;
public static class Bean extends Base
public final String field2;
public Bean(final String field1, final String field2)
super(field1);
this.field2 = field2;
private static class IgnoreInheritedIntrospector extends JacksonAnnotationIntrospector
@Override
public boolean hasIgnoreMarker(final AnnotatedMember m)
return m.getDeclaringClass() == Base.class || super.hasIgnoreMarker(m);
public static void main(String[] args) throws JsonProcessingException
final ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(new IgnoreInheritedIntrospector());
final Bean bean = new Bean("a", "b");
System.out.println(mapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(bean));
输出:
“字段2”:“b”
【讨论】:
这个解决方案对我有用。太忽略复杂的 JOOQ 基类,我的hasIgnoreMarker
实现是return m.getDeclaringClass().getName().contains("org.jooq") || super.hasIgnoreMarker(m)
【参考方案2】:
您可以覆盖您希望阻止输出的超类方法并使用@JsonIgnore 对其进行注释。覆盖将属性创建的控制转移到子类,同时使其能够从输出中过滤它。
例如:
public class SomeClass
public void setField1(...);
public Integer getField1();
public void setField2(...);
public Integer getField2();
@Override
@JsonIgnore
public String superClassField1(...)
return super.superClassField1();
;
@Override
@JsonIgnore
public String superClassField2(...)
return super.superClassField2();
;
...
【讨论】:
补充@AbhishekChatterjee 的观点,jackson 使用对象中的 getter 来确定要显示的内容,因此只有 getter 需要被覆盖。【参考方案3】:您也可以使用它来代替不必要的覆盖
@JsonIgnoreProperties( "aFieldFromSuperClass")
public class Child extends Base
private String id;
private String name;
private String category;
【讨论】:
【参考方案4】:继承的好处是子类扩展或添加功能。所以通常的做法是对数据进行序列化。
解决方法是将值对象 (VO) 或数据传输对象 (DTO) 与您需要序列化的字段一起使用。步骤:
使用应序列化的字段创建一个 VO 类。 使用 BeanUtils.copyProperties(target VO, source data) 复制属性 序列化 VO 实例。【讨论】:
在这种情况下,这将是纯粹的复制粘贴。使用生成的类的重点是避免重复我的模式信息(字段、类型等)。理想情况下,一个字段的名称应该只输入一次——在我的 SQL 模式中(或者在 ORM 的情况下在手写的 POJO 中)。到目前为止,这在我的设计中或多或少是正确的,我不想打破它。 否则需要重新定义子类上的字段,并标记为“不可序列化”。 @Ferenc:您可以让 jOOQ 为您生成所有这些 POJO / VO / DTO:jooq.org/doc/latest/manual/code-generation/codegen-pojos 是的,这是另一种可能的解决方案——我已经使用了 POJO,所以 select 方法上的一个简单的 .into(MyGenerated.class) 也可以做到。谢谢!【参考方案5】:在您的基类中添加以下注释:
@JsonInclude(Include.NON_NULL)
【讨论】:
以上是关于Jackson 序列化:如何忽略超类属性的主要内容,如果未能解决你的问题,请参考以下文章
在 Java 中的 Jackson JSON 反序列化期间忽略丢失的属性
jackson 常用注解,比如忽略某些属性,驼峰和下划线互转
详解jackson注解(三)jackson包含属性、忽略属性的注解