如何利用Jackson序列化忽略指定类型的属性详解

2025-05-29 0 100

前言

本文准确来讲是探讨如何用 jackson 来序列化 apache avro 对象,因为简单用 jackson 来序列化 apache avro 对象会报错。原因是序列化 schema getschema() 时会报错,后面会讲到,需要序列化时忽略该属性。那么能不能在 getschema() 上加上 @jsonignore 来忽略该属性呢?原理上是通的。不过手工修改的 avsc 生成的 java 文件随时会因为重新编译而还原,所以不太具有实际可操作性,当然通过定制编译 avsc 用的模板文件来加入 @jsonignore 是另一回事。

由于不能在要忽略的字段上添加 jsonignore 来控制,而如果我们明确了要忽略的字段类型的话,是能够定制 jackson 的 objectmapper 来屏蔽某个特定的类型。来看下面序列化 apache avro 对象的例子:

假设我们有一个 apache 的 schema 文件 user.avsc, 内容如下:

?

1

2

3

4

5

6

7

8

9
{

"namespace": "cc.unmi.data",

"type": "record",

"name": "user",

"fields": [

{"name": "name", "type": "string"},

{"name": "address", "type": ["string", "null"]}

]

}

编译用 avro-tools compile schema user.avsc . 生成 cc.unmi.data.user.java 源文件,当我们试图对类型的对象用 jackson 进行序列化

?

1

2

3
objectmapper objectmapper = new objectmapper() ;

user user = user.newbuilder().setname("yanbin").setaddress("chicago").build();

system.out.println(objectmapper.writevalueasstring(user));

收到异常(关键信息)

caused by: org.apache.avro.avroruntimeexception: not a map: {"type":"record","name":"user","namespace":"cc.unmi.data","fields":[{"name":"name","type":"string"},{"name":"address","type":["string","null"]}]}
at org.apache.avro.schema.getvaluetype(schema.java:294)
at com.fasterxml.jackson.databind.ser.beanpropertywriter.serializeasfield(beanpropertywriter.java:664)
at com.fasterxml.jackson.databind.ser.std.beanserializerbase.serializefields(beanserializerbase.java:689)

从上面的错误可以定位到 jackson 的试图序列化 user 对象的

?

1
public org.apache.avro.schema getschema() { return schema$; }

而 org.apache.avro.schema 中的 getvaluetype() 直接抛出异常拒绝被归化

?

1

2

3
public schema getvaluetype() {

throw new avroruntimeexception("not a map: "+this);

}

因此,要实现序列化 apache avro 对象,解决的办法有三

  • 凡是 org.apache.avro.schema 的属性不被序列化(schema 输出确实用处不大)
  • 或对于org.apache.avro.schema 类型的属性定制序列化,比如输出为完整类名,或 schema 定义的文本内容
  • 再来一个,对 specificrecordbase 类型的 schema 名称的属性进行忽略(avro 类型继承自 specificrecordbase)

它们的实现分别如下

忽略序列化指定类型的属性

先定义一个标注了 @jsonignoretype 的注解

?

1

2

3
@jsonignoretype

@interface ignoreavroschemafield {

}

序列化 apache avro 对象前给 objectmapp 加一个 mixin

?

1

2

3

4

5
objectmapper objectmapper = new objectmapper() ;

objectmapper.addmixin(schema.class, ignoreavroschemafield.class);

user user = user.newbuilder().setname("yanbin").setaddress("chicago").build();

system.out.println(objectmapper.writevalueasstring(user));

有了上面高度行的代码,这儿的 apache avro user 对象就能被正常序列化了,输出为

{"name":"yanbin","address":"chicago"}

这样 getschema() 返回的类型,或另何对象中有 org.apache.avro.schema 类型的属性都会在序列化时忽略掉

定制 schema 属的输出内容

对于 schema 类型的属性,除了前面采取堵的方式,还可以因利疏导,即定制 schema 属性值的输出内容

定制化 schema 序列化方式

?

1

2

3

4

5

6

7
class avroschemaserializer extends jsonserializer<schema> {

@override

public void serialize(schema value, jsongenerator jgen, serializerprovider provider) throws ioexception {

jgen.writestring(value.getfullname()); //直接输出当前 apache avro 对象的全限类名

}

}

给 objectmapper 加上定制的序列化

?

1

2

3

4

5

6

7
objectmapper objectmapper = new objectmapper() ;

simplemodule simplemodule = new simplemodule("simplemodule", version.unknownversion());

simplemodule.addserializer(schema.class, new avroschemaserializer());

objectmapper.registermodule(simplemodule);

user user = user.newbuilder().setname("yanbin").setaddress("chicago").build();

system.out.println(objectmapper.writevalueasstring(user));

序列化后产生的输出如下

{"name":"yanbin","address":"chicago","schema":"cc.unmi.data.user"}

如果在 avroschemaserializer 把 jgen.writestring(value.getfullname()) 替换如下

?

1
jgen.writestring(value.tostring());

并且序列化后对内容进行格式化输出

?

1

2

3

4

5

6
system.out.println(objectmapper.writerwithdefaultprettyprinter().writevalueasstring(user));

{

"name" : "yanbin",

"address" : "chicago",

"schema" : "{\\"type\\":\\"record\\",\\"name\\":\\"user\\",\\"namespace\\":\\"cc.unmi.data\\",\\"fields\\":[{\\"name\\":\\"name\\",\\"type\\":\\"string\\"},{\\"name\\":\\"address\\",\\"type\\":[\\"string\\",\\"null\\"]}]}"

}

指定特定对象的属性名进行过滤

从语义上除了 ignore 外,filter 也像是干这事的,可以尝试过下面的方式, 分两步走

定义一个带 @jsonfilter 的注解,也是不显示注解到任何类

?

1

2
@jsonfilter("filter out apache avro schema field") //字符串值要与下面 addfilter("xxx") 保持一致

class propertyfiltermixin {}

给 objectmapper 设置 filter

?

1

2

3

4

5

6

7

8
objectmapper objectmapper = new objectmapper() ;

objectmapper.addmixin(specificrecordbase.class, propertyfiltermixin.class); //对 specificrecordbase 类型的对象应用

filterprovider filterprovider = new simplefilterprovider() //对 specificrecordbase 类型(如 user) 的名为 "schema" 属性屏蔽

.addfilter("filter out apache avro schema field", simplebeanpropertyfilter.serializeallexcept("schema"));

objectmapper.setfilterprovider(filterprovider);

user user = user.newbuilder().setname("yanbin").setaddress("chicago").build();

system.out.println(objectmapper.writevalueasstring(user));

输出效果没有意外,也能避免序列化 schema 属性

{"name":"yanbin","address":"chicago"}

这最后一种方式是本篇写作行将结束时找到并验证的,所以不写出来,不进行梳理可能永远只会第一种方法。

链接:

  • jackson ignore properties on marshalling
  • how do i exclude fields with jackson not using annotations

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对快网idc的支持。

原文链接:https://yanbin.blog/jackson-ignore-specified-field-type/

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 如何利用Jackson序列化忽略指定类型的属性详解 https://www.kuaiidc.com/111106.html

相关文章

发表评论
暂无评论