Java POJO转Avro GenericRecord时遇NoClassDefFoundError求助
问题排查与解决方案
问题背景
尝试通过KafkaAvroSerializer将Java POJO转换为Avro格式发送到Kafka,但在转换为GenericRecord时触发NoClassDefFoundError,异常发生在初始化AvroMapper实例的语句处。
报错信息
java.lang.NoClassDefFoundError: Failed to link com/fasterxml/jackson/dataformat/avro/AvroParser$Feature (Module "deployment.MyAppModule.ear:main" from Service Module Loader): com/fasterxml/jackson/core/FormatFeature
转换代码
public static GenericRecord convertPojoToGenericRecord(String schemaPath, MyMessageClass message){ InputStream inStream = MyAppClass.class.getClassLoader().getResourceAsStream(schemaPath); Schema schema = new Schema.Parser().setValidate(true).parse(inStream); AvroSchema avSchema = new AvroSchema(schema); AvroMapper avroMapper = new AvroMapper(); // 异常触发点 final byte[] bytes = avroMapper.writer(avSchema).writeValueAsBytes(message); GenericDatumReader<Object> genericRecordReader = new GenericDatumReader<>(avSchema); return (GenericRecord) genericRecordReader.read(null, DecoderFactory.get().binaryDecoder(bytes, null)); }
依赖情况
使用的Maven依赖(版本均为2.9.10):
- jackson-dataformat-avro
- jackson-core
- jackson-databind
- jackson-annotations
- jackson-jars-json-provider
- jackson-datatype-joda
通过依赖树排查发现,jackson-dataformat-avro默认依赖了2.5.4版本的jackson-databind,导致版本冲突。且应用部署在JBoss 10服务器上,因属于遗留系统无法升级Jackson版本(其他模块依赖当前版本)。
解决方案
1. 强制统一Jackson依赖版本
在Maven的pom.xml中,给jackson-dataformat-avro添加依赖排除,手动指定统一的2.9.10版本,避免依赖树引入旧版本:
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-avro</artifactId> <version>2.9.10</version> <exclusions> <exclusion> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> </exclusion> <exclusion> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </exclusion> <exclusion> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> </exclusion> </exclusions> </dependency> <!-- 显式声明统一版本的核心依赖 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.10</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.10</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.10</version> </dependency>
2. 配置JBoss类加载优先级
JBoss可能自带旧版本Jackson类,需在jboss-deployment-structure.xml中配置类加载规则,让应用优先使用自身打包的Jackson版本:
<jboss-deployment-structure> <deployment> <exclusions> <module name="com.fasterxml.jackson.core.jackson-core"/> <module name="com.fasterxml.jackson.core.jackson-databind"/> <module name="com.fasterxml.jackson.core.jackson-annotations"/> </exclusions> </deployment> </jboss-deployment-structure>
将该文件放置在EAR包的META-INF目录下,确保应用加载自身的Jackson库,避免与容器自带版本冲突。
3. 替代转换方案(若依赖冲突无法解决)
如果上述方法无效,可绕过Jackson的Avro转换模块,直接使用Avro原生工具:
- 通过
avro-maven-plugin根据Avro Schema生成对应的Java类 - 将自定义
MyMessageClass的数据拷贝到生成的Avro POJO中 - 直接使用Avro的
GenericRecord相关API完成转换,无需依赖Jackson的Avro模块
内容的提问来源于stack exchange,提问作者Avinash
相关产品推荐
相关产品推荐

