使用Jackson ObjectMapper处理嵌套Avro对象转JSON异常的方案问询
解决Jackson ObjectMapper转换嵌套Avro对象为JSON的异常问题
问题场景
给定JSON Payload:
{"tradeQuantity":13,"tradeMarket":"sssss","stockName":"teststock","tradeType":"testtype","price":12.2,"amount":12.5,"address":{"stret" : "aaa","city" : "bbb" }}
Avro类实例化代码:
StockHistory stockHistory= new StockHistory(); stockHistory.setStockName(model.getStockName()); stockHistory.setTradeType(model.getTradeType()); stockHistory.setPrice(model.getPrice()); stockHistory.setAmount(model.getAmount()); stockHistory.setTradeId(new Random(1000).nextInt()); stockHistory.setTradeMarket(model.getTradeMarket()); stockHistory.setTradeQuantity(model.getTradeQuantity()); Address address = new Address(); address.setCity("sss"); address.setStreetaddress("aaaa"); stockHistory.setAddress(address);
使用普通Jackson ObjectMapper转换时:
ObjectMapper mapper = new ObjectMapper(); mapper.addMixIn(StockHistory.class, IgnoreSchemaProperty.class); mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
仅当StockHistory无嵌套Address时转换正常,包含嵌套对象时抛出异常:
org.apache.avro.AvroRuntimeException: Not an array: {"type":"record","name":"Address","namespace":"com.spring.cloud.streams.avro","fields":[{"name":"streetaddress","type":["null","string"],"default":null},{"name":"city","type":["null","string"],"default":null}]}
解决方案
使用Jackson官方提供的Avro数据格式模块(jackson-dataformat-avro),它专门适配Avro生成的类,能正确处理嵌套Avro对象的序列化/反序列化。
步骤1:引入依赖
如果使用Maven,在pom.xml中添加:
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-avro</artifactId> <version>2.15.2</version> <!-- 版本需与你的Jackson核心版本保持一致 --> </dependency>
步骤2:替换ObjectMapper为AvroMapper
修改代码,用AvroMapper替代普通ObjectMapper:
import com.fasterxml.jackson.dataformat.avro.AvroMapper; import com.fasterxml.jackson.databind.DeserializationFeature; // 创建Avro专用的Mapper实例 AvroMapper mapper = new AvroMapper(); mapper.addMixIn(StockHistory.class, IgnoreSchemaProperty.class); mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // 序列化Avro对象到JSON String jsonOutput = mapper.writeValueAsString(stockHistory); // 从JSON反序列化回Avro对象 StockHistory parsedHistory = mapper.readValue(jsonOutput, StockHistory.class);
原因分析
普通ObjectMapper未针对Avro生成类的特殊结构做适配,Avro类内部包含schema相关属性,处理嵌套对象时,Jackson默认的反射逻辑会触发Avro内部校验,导致类型错误。而AvroMapper专门针对Avro的record结构、嵌套类型做了适配,能正确识别并处理嵌套Avro对象。
Google GSON能正常运行是因为其默认字段遍历逻辑更宽松,自动跳过了Avro内部的schema字段,未触发校验,但这种方式无Avro专属适配,长期稳定性不如官方模块。
内容的提问来源于stack exchange,提问作者Aleem
相关产品推荐
相关产品推荐

