Skip to content
Advertisement

Spring Boot 2.6.4 -> 2.6.6 : strange NullPointerException within Logback when logging a mock Exception

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.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement