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 ?
Advertisement
Answer
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 in build.gradle
file.
ext["logback.version"] = "1.2.10"
If you’re using Maven dependencyManagement
section for Spring Boot dependencies instead of the starter parent then you can try this:
<!-- ... --> <dependencyManagement> <dependencies> <!-- temp. override logback version for https://jira.qos.ch/browse/LOGBACK-1623--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-access</artifactId> <version>1.2.10</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.10</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.10</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.7.5</version> <type>pom</type> <scope>import</scope> </dependency> </dependencyManagement> <!-- ... -->
Update: Spring Boot 2 latest version (2.7.5) is still using logback:1.2.11
.