升级至CXF 3.4.1后调用WSDLToJava触发Hashtable空指针异常及存在NOPLogger时VelocityGenerator初始化失败问题求助
这俩问题本质上是同一类冲突的不同表现,核心都是Velocity日志系统和SLF4J的NOPLogger打架,导致初始化时往不允许存null的Hashtable里塞了null值,直接触发空指针异常。
详细根源拆解
问题1:AbstractGenerator调用new VelocityGenerator(false)抛NPE
当类路径里有org.slf4j.helpers.NOPLogger时,Velocity会自动尝试绑定SLF4J作为日志实现,但NOPLogger是个空日志壳子,会让Velocity初始化时的某些日志配置属性被解析成null。而Velocity内部用Hashtable存配置(这货严格禁止键或值为null),一碰到null就直接炸NPE。
问题2:升级CXF 3.4.1后WSDLToJava触发Hashtable NPE
CXF 3.4.1升级了依赖的Velocity版本,或者调整了Velocity的初始化逻辑,把之前隐藏的冲突直接暴露出来了。从堆栈能看到,异常从ExtendedProperties.addPropertyInternal调用Hashtable.put开始,就是Velocity加载配置时,把某个日志相关的null值往Hashtable里塞导致的——还是NOPLogger搞的鬼。
具体修复方案
根据你的场景选对应的方案就行:
方案1:删掉冗余的NOPLogger依赖
如果NOPLogger是项目里误加的(比如不小心引入了slf4j-nop包),直接把它从依赖里踢出去:
- Maven项目:在pom.xml里排除或者删除依赖
<!-- 如果是误引入的,直接删掉这个依赖块 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-nop</artifactId> <scope>provided</scope> </dependency>
- Gradle项目:
configurations.all { exclude group: 'org.slf4j', module: 'slf4j-nop' }
方案2:强制指定Velocity的日志实现
如果必须保留NOPLogger(比如项目确实需要空日志场景),那就手动告诉Velocity用哪个日志实现,别让它自动绑定SLF4J:
- 启动程序时加JVM参数:
-Dvelocity.log.system.class=org.apache.velocity.runtime.log.NullLogChute
- 或者在代码里初始化Velocity前手动配置:
Properties velocityProps = new Properties(); velocityProps.put("runtime.log.logsystem.class", "org.apache.velocity.runtime.log.NullLogChute"); Velocity.init(velocityProps);
针对CXF的WSDLToJava,可以在启动脚本里加上上面的JVM参数,或者通过CXF的工具配置文件指定这个日志实现。
方案3:升级依赖版本(针对问题2)
检查CXF 3.4.1依赖的Velocity版本,试试升级到修复了这个冲突的版本(比如Velocity 1.7.1+或者2.x系列),或者直接升级到更高版本的CXF(比如3.4.5及以上,官方可能已经修复了这个依赖冲突问题)。
验证步骤
修复完之后,做这俩检查确认没问题:
- 重新调用
new VelocityGenerator(false),看是否还会抛NPE; - 运行
WSDLToJava工具,检查能不能正常加载AntGenerator并完成代码生成。
内容的提问来源于stack exchange,提问作者Aaron Digulla

