时间:2021-05-19
前言
本文准确来讲是探讨如何用 Jackson 来序列化 Apache avro 对象,因为简单用 Jackson 来序列化 Apache avro 对象会报错。原因是序列化 Schema getSchema() 时会报错,后面会讲到,需要序列化时忽略该属性。那么能不能在 getSchema() 上加上 @JsonIgnore 来忽略该属性呢?原理上是通的。不过手工修改的 avsc 生成的 Java 文件随时会因为重新编译而还原,所以不太具有实际可操作性,当然通过定制编译 avsc 用的模板文件来加入 @JsonIgnore 是另一回事。
由于不能在要忽略的字段上添加 JsonIgnore 来控制,而如果我们明确了要忽略的字段类型的话,是能够定制 Jackson 的 ObjectMapper 来屏蔽某个特定的类型。来看下面序列化 Apache avro 对象的例子:
假设我们有一个 Apache 的 Schema 文件 user.avsc, 内容如下:
{ "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 进行序列化时
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 对象的
public org.apache.avro.Schema getSchema() { return SCHEMA$; }而 org.apache.avro.Schema 中的 getValueType() 直接抛出异常拒绝被归化
public Schema getValueType() { throw new AvroRuntimeException("Not a map: "+this); }因此,要实现序列化 Apache avro 对象,解决的办法有三
它们的实现分别如下
忽略序列化指定类型的属性
先定义一个标注了 @JsonIgnoreType 的注解
@JsonIgnoreType@interface IgnoreAvroSchemaField {}序列化 Apache avro 对象前给 ObjectMapp 加一个 mixin
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 序列化方式
class AvroSchemaSerializer extends JsonSerializer<Schema> { @Override public void serialize(Schema value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeString(value.getFullName()); //直接输出当前 Apache avro 对象的全限类名 }}给 ObjectMapper 加上定制的序列化器
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()) 替换如下
jgen.writeString(value.toString());并且序列化后对内容进行格式化输出
指定特定对象的属性名进行过滤
从语义上除了 Ignore 外,Filter 也像是干这事的,可以尝试过下面的方式, 分两步走
定义一个带 @JsonFilter 的注解,也是不显示注解到任何类
@JsonFilter("filter out apache avro schema field") //字符串值要与下面 addFilter("xxx") 保持一致class PropertyFilterMixIn {}给 ObjectMapper 设置 filter
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"}
这最后一种方式是本篇写作行将结束时找到并验证的,所以不写出来,不进行梳理可能永远只会第一种方法。
链接:
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
详解Python序列化Serialize和反序列化Deserialize序列化(serialization)序列化是将对象状态转换为可保持或传输的格式的过程。与
本文讲解使用jaxb结合dom4j的XMLFilterImpl过滤器实现序列化和反序列化的完全控制主要实现以下功能序列化及反序列化时忽略命名空间
1、描述@JsonInclude(JsonInclude.Include.NON_NULL)标记是jackson包提供的json序列化方法,已经集成于Sprin
Java序列化和反序列化实例详解在分布式应用中,对象只有经过序列化才能在各个分布式组件之间传输,这就涉及到两个方面的技术-发送者将对象序列化,接受者将对象反序列
写在前面,首先,我用的java转json序列化的工具是java开源的jackson。今天在做后端接口的时候,发现获取的json对象中少了几个属性,因为其他的接口