Spring Boot 2.6.4 -> 2.6.6:记录模拟异常时,Logback 中出现奇怪的 NullPointerException
从 Spring Boot 2.6.4 升级到 2.6.6 时,我的一项测试(用 Kotlin 编写)失败了:
@Test
fun shouldLogProperMessageIfNotAbleToHitAPI() {
val configValidator = ConfigValidator(GitHubCrawlerProperties(SourceControlConfig(url = "someIncorrectURL",organizationName="someOrg")),mockRemoteSourceControl)
`when`(mockRemoteSourceControl.validateRemoteConfig("someOrg")).thenThrow(NoReachableRepositories("problem !",mock(Exception::class.java)))
val validationErrors=configValidator.getValidationErrors()
assertThat(validationErrors).hasSize(1);
}
Spring Boot 2.6.4 的构建通过了。当我在 IDE 中单独运行测试时,它在 Spring Boot 2.6.6 中工作,但在 Maven 构建过程中失败。
默认情况下,堆栈跟踪未显示,但在通过 try/catch 包围调用后,我能够获取它,并且它指向 Logback :
java.lang.NullPointerException: null
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:99)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:89)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:62)
at ch.qos.logback.classic.spi.LoggingEvent.<init>(LoggingEvent.java:119)
at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:419)
at ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:383)
at ch.qos.logback.classic.Logger.error(Logger.java:538)
at com.societegenerale.githubcrawler.ConfigValidator.getValidationErrors(ConfigValidator.kt:48)
Logback 版本似乎没有更改,我仍然得到 v 1.2.11 。
查看 Logback 源代码,在 ThrowableProxy 中:
if (GET_SUPPRESSED_METHOD != null) {
// this will only execute on Java 7
Throwable[] throwableSuppressed = extractSupressedThrowables(throwable);
if (throwableSuppressed.length > 0) {
List<ThrowableProxy> suppressedList = new ArrayList<ThrowableProxy>(throwableSuppressed.length);
for (Throwable sup : throwableSuppressed) {
...
注意:我使用 Java 11 构建,因此 Logback 源代码中的注释说 this will onlyexecute on Java 7
,似乎是错误的。
似乎 throwableSuppressed 为 null,当调用 throwableSuppressed.size 时我得到了 NPE。
如果我没有在 NoReachableRepositories("problem !",mock(Exception::class.java))
中使用模拟,而是使用 NoReachableRepositories("problem !",Exception() ,则测试通过)
我意识到使用真正的异常可能比使用模拟更好,所以我的问题以某种方式解决了(在花了 2 个小时之后......)。
但是,我很好奇:升级到 Spring Boot 2.6.6 后,什么可能会导致这个问题,这应该是一个微小的变化?
while upgrading from Spring Boot 2.6.4 to 2.6.6 , one of my tests (written in Kotlin), fails :
@Test
fun shouldLogProperMessageIfNotAbleToHitAPI() {
val configValidator = ConfigValidator(GitHubCrawlerProperties(SourceControlConfig(url = "someIncorrectURL",organizationName="someOrg")),mockRemoteSourceControl)
`when`(mockRemoteSourceControl.validateRemoteConfig("someOrg")).thenThrow(NoReachableRepositories("problem !",mock(Exception::class.java)))
val validationErrors=configValidator.getValidationErrors()
assertThat(validationErrors).hasSize(1);
}
the build passes with Spring Boot 2.6.4. It works in Spring Boot 2.6.6 when I run the test individually in my IDE, but fails during the maven build.
the stacktrace was not showing by default, but after surrounding the call by a try/catch, I am able to get it, and it points to Logback :
java.lang.NullPointerException: null
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:99)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:89)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:62)
at ch.qos.logback.classic.spi.LoggingEvent.<init>(LoggingEvent.java:119)
at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:419)
at ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:383)
at ch.qos.logback.classic.Logger.error(Logger.java:538)
at com.societegenerale.githubcrawler.ConfigValidator.getValidationErrors(ConfigValidator.kt:48)
Logback version doesn't seem to change, I still get v 1.2.11 .
Looking at Logback source code, in ThrowableProxy :
if (GET_SUPPRESSED_METHOD != null) {
// this will only execute on Java 7
Throwable[] throwableSuppressed = extractSupressedThrowables(throwable);
if (throwableSuppressed.length > 0) {
List<ThrowableProxy> suppressedList = new ArrayList<ThrowableProxy>(throwableSuppressed.length);
for (Throwable sup : throwableSuppressed) {
...
note : I build with Java 11, so the comment saying in Logback source code that this will only execute on Java 7
, seems wrong.
It seems that throwableSuppressed
is null, and I get the NPE when throwableSuppressed.size
is called.
The test passes if instead of using a mock in NoReachableRepositories("problem !",mock(Exception::class.java))
, I use NoReachableRepositories("problem !",Exception())
I realize it's probably better to use a real Exception rather than a mock, so my problem is solved in a way (after spending 2 hours on this..).
However, I am curious : what could cause this issue after upgrading to Spring Boot 2.6.6 which should be a a minor change ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
此问题是由 在
logback:1.2.11
中引入的href="https://github.com/qos-ch/logback/commit/398aa4bd8f2bc0bb7f1465e8f7aca418 c4464c15#diff-91f381102ba772e2944bcc4d01e615b39d0f366a91b9dddd05b29d736cbea9c1" rel="noreferrer">提交。在此 Jira 票据 中对其进行跟踪。Logback
从spring boot 2.6.5升级到1.2.11,可以参考这个变更日志。因此,如果您升级到 2.6.5,您也会遇到同样的错误。我们现在可以做的是通过在
build.gradle
文件中添加此行来将logback
版本覆盖到 1.2.10。如果您使用 Maven
dependencyManagement
部分来获取 Spring Boot 依赖项,而不是起始父级,那么您可以尝试以下操作:更新:Spring Boot 2 最新版本 (2.7.5) 是仍在使用
logback:1.2.11
。This issue was introduced in
logback:1.2.11
by this commit. It is tracked in this Jira ticket.Logback
was upgraded to 1.2.11 from spring boot 2.6.5, you can refer to this changelog. So you would have encountered this same error if you upgraded to 2.6.5.What we can do now is override the version of
logback
to 1.2.10 by adding this line inbuild.gradle
file.If you're using Maven
dependencyManagement
section for Spring Boot dependencies instead of the starter parent then you can try this:Update: Spring Boot 2 latest version (2.7.5) is still using
logback:1.2.11
.如果仅用于测试,则可以模拟LoggerFactory
If it is just for tests you can mock the LoggerFactory