项目清况
项目中有两个包都引用了jackson 的包且都是不再更新的版本
javascript
// jarA 包中引入 org.codehaus.jackson 包 1.8.4 版本
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.8.4</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.8.4</version>
</dependency>
//jar B 包中引入了 org.codehaus.jackson 包 1.9.13 版本
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
// org.codehaus.jackson 包最后在 2013 年的时候发生了组织变化(fastxml) ,且后续不再维护
// 如今正确使用jackson 应该引入以下的 3 个包:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.17.1</version>
</dependency>
从上面包中看得出,项目有些年代感了(springmvc 3.x 的版本,打包成war 部署运行),本着能运行的情况下,绝不随意改动的原则,还是继续使用 org.codehaus.jackson
这个包
报错、异常
web 项目 能正常编译,运行时也正常启动,但执行到需要调用 org.codehaus.jackson 包中的某个方法时,产生运行异常:NoSuchMethodError:org.codehaus.jackson.map.ObjectMapper.setSerializationInclusion
找到报错处是 jarB 中的程序片段异常,找到对应代码中引用的包,定位后发现确实不存在这个方法,此时打开的是 1.8.4 的版本,(jarB 需要 1.9.13 版本的包)
处理冲突
找到问题了就好说,1.9与 1.8的版本应该上线兼容,则采用 1.9 的版本即可, 那么我们只需要在 jarA 中排除掉 1.8.4 的jackson 应该就能解决问题
xml
<dependency>
<groupId>org.china.xxxx</groupId>
<artifactId>jarA</artifactId>
<version>x.x.x</version>
// 排除 ,jarA 中对低版本的引入
<exclusion>
<artifactId>jackson-core-asl</artifactId>
<groupId>org.codehaus.jackson</groupId>
</exclusion>
<exclusion>
<artifactId>jackson-mapper-asl</artifactId>
<groupId>org.codehaus.jackson</groupId>
</exclusion>
</dependency>
做了这个动作之后发现,项目中的已换成 1.9.13 版本
可以 使用 Maven Helper 工具来查看依赖冲突,exclude 包等
排除后充新编译项目启动运行,发现仍然
NoSuchMethodError:org.codehaus.jackson.map.ObjectMapper.setSerializationInclusion
进一步探究
- 编写单元测试 方法调用,发现单元测试没问题
📖 说明问题出在 Tomcat, 编译没问题说明包引入正常(idea 中包依赖显示正常,且跟踪代码也能找到正确的包) 问题应该出在 ClassLoad → 类加在上
- tomcat 启动项 增加
-XX:+TraceClassLoading -XX:+TraceClassUnloading
tomcat 启动后发现,jackson 仍然加载 1.8.4 的版本
- 根据步骤 2 查看对应的目录发现,存在多个版本的包(但低版本的我应该排除掉了才对), 这个目录在 idea 项目的 target目录下
target/项目名称/WEB-INF/lib
结合了解到tomcat 加载 lib 目录下的包时,会按照顺序加在,且同样的包只会加在一次,所以,这里应该是优先加在了 1.8.4 所以后续引入的 1.9 就被忽略
那么问题来了-》 dependency 中 exclusion 排除了 低版本的包,是怎么又出现在 lib 中的,
发现问题
最后仔细观察 发现 jarA 是作为父项目,引入到当前项目中的
overlay 的资源会被覆盖到当前项目中,包括,WEB-INF 下的所有lib 这也是为什么在 lib 目录下仍然存在 1.8.4 版本的包. 需要在 overlay 中也将相应的包剔除
xml
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<overlays>
<overlay>
<groupId>com.unionman</groupId>
<artifactId>unionmanframe</artifactId>
<excludes>
<exclude>**/jackson-core-asl-1.8.4.jar</exclude>
<exclude>**/jackson-mapper-asl-1.8.4.jar</exclude>
</excludes>
</overlay>
</overlays>
</configuration>
</plugin>
...
最后再次启动,类正常加载 jackson-1.9.13 包