Skip to main content
  1. posts/

kotlin1.2升级1.3踩坑

·1190 words·3 mins

现象

在对项目的kotlin版本从1.2升级到1.3的时候,有一个很奇怪的现象。我觉得值得一提。当然,也不得不感谢大佬的博客让我受益匪浅。 现象是这样的,项目的kotlin版本从1.2升级到1.3之后,在idea中debug启动是正常启动的。但是当我用jar包启动时,就会报错 Ambiguous mapping. 然后,代码是没有改动的,就仅仅改动到一些pom文件。 tips: . 大概意思就是mapping重复了。

image.png

分析

1.2能正常工作,1.3就报错。不会是字节码在搞鬼吧。 看看这个报错的类生成的字节码。 kotlin1.2

image.png

kotlin1.3

image.png
image.png

看起来就只有一个差异了,1.2多了一个bridge。 不会是这个原因吧。 到这里好像也并没有什么思路,我怎么知道这个bridge究竟是怎么影响到mapping处理的呢。所以还是得看看mapping的处理过程。

SpringMVC处理Mapping

接下来应该去看看springmvc是怎么处理Mapping的。这一个咋一看,好像没什么思路,只有google。也没什么答案。但是呢,作为一个程序员,解决问题不能全靠google吧。还是要学会正向解决问题。记得之前梳理过spring的启动过程。

从实现思路来看,应该会在初始化类之后,解析对应的mapping放入到一个map中。这个从报错日志也能发现端倪。

at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.assertUniqueMethodMapping(AbstractHandlerMethodMapping.java:576) ~[spring-webmvc-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.register(AbstractHandlerMethodMapping.java:540) ~[spring-webmvc-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.registerHandlerMethod(AbstractHandlerMethodMapping.java:264) ~[spring-webmvc-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.detectHandlerMethods(AbstractHandlerMethodMapping.java:250) ~[spring-webmvc-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods(AbstractHandlerMethodMapping.java:214) ~[spring-webmvc-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
	at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.afterPropertiesSet(AbstractHandlerMethodMapping.java:184) ~[spring-webmvc-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.afterPropertiesSet(RequestMappingHandlerMapping.java:127) ~[spring-webmvc-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687) ~[spring-beans-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624) ~[spring-beans-4.3.9.RELEASE.jar!/:4.3.9.RELEASE]
	... 24 more

从这个流程来看的话,大概率是检测handlerMethods会不一致,导致有bridge标志符的会被过滤掉,我们就来细看这个detectHandlerMethods方法。 果然,detectHandlerMethods内部有个MethodIntrospector.selectMethods调用,这个内部用了ReflectionUtils.USER_DECLARED_METHODS。 里面就是判断哪些方法需要进入mapping map的。
image.png
到这里,我们就能知道,为啥kotlin1.2版本没有这个问题,而kotlin1.3编译的字节码会存在这个问题了。

那怎么解决呢?

按这个逻辑来讲,kotlin1.3和spring-webmvc.4.3.11不是水火不容吗? 这样的话,应该有两种解决方式,要么spring解决非桥接方法问题,要么kotlin解决mapping问题。总不能我重写spring的类吧

Spring解决方式

让我们来看看spring5.x的ReflectionUtils.USER_DECLARED_METHODS。多了一个isSynthetic,刚好kotlin1.3也有这个AccessFlag.

image.png

Kotlin解决方式

kotlin升级到1.4.21也能解决,原因是getQuestionList$default没有mapping了

image.png

总结

  1. Idea可能会骗人,字节码永远不会
  2. 不熟悉流程时,调用链非常关键。结合处理流程和调用链报错,反猜问题根因是一个不错的方式。

参考

https://juejin.cn/post/7083666557313744932