Skip to content
This repository was archived by the owner on Feb 23, 2023. It is now read-only.

NPE during AOT generation when @ConfigurationProperties contains generic property #1396

Closed
nbruno opened this issue Dec 21, 2021 · 1 comment
Assignees
Labels
type: bug A general bug
Milestone

Comments

@nbruno
Copy link

nbruno commented Dec 21, 2021

With a dependency on consul-api and a @ConfigurationProperties bean that contains a ConsulClient field, AOT generation fails with a NullPointerException. While this particular use-case may be strange (having a ConsulClient field within @ConfigurationProperties), there is a more general case that reproduces this issue.

The dependency to add (Gradle):

implementation 'com.ecwid.consul:consul-api:1.4.5'

The properties class:

@ConfigurationProperties(prefix = "example")
public class DemoProperties {
    private ConsulClient consulClient;

    public void setConsulClient(ConsulClient consulClient) {
        this.consulClient = consulClient;
    }

    public ConsulClient getConsulClient() {
        return consulClient;
    }
}

Enable it with @EnableConfigurationProperties(DemoProperties.class) and you get:

java.lang.NullPointerException
    at org.springframework.boot.context.properties.ConfigurationPropertiesNativeConfigurationProcessor$TypeProcessor.handleJavaBeanProperties(ConfigurationPropertiesNativeConfigurationProcessor.java:156)
    at org.springframework.boot.context.properties.ConfigurationPropertiesNativeConfigurationProcessor$TypeProcessor.process(ConfigurationPropertiesNativeConfigurationProcessor.java:112)
    at org.springframework.boot.context.properties.ConfigurationPropertiesNativeConfigurationProcessor$TypeProcessor.process(ConfigurationPropertiesNativeConfigurationProcessor.java:94)
    at org.springframework.boot.context.properties.ConfigurationPropertiesNativeConfigurationProcessor$TypeProcessor.handleJavaBeanProperties(ConfigurationPropertiesNativeConfigurationProcessor.java:159)
    at org.springframework.boot.context.properties.ConfigurationPropertiesNativeConfigurationProcessor$TypeProcessor.process(ConfigurationPropertiesNativeConfigurationProcessor.java:112)
    at org.springframework.boot.context.properties.ConfigurationPropertiesNativeConfigurationProcessor$TypeProcessor.process(ConfigurationPropertiesNativeConfigurationProcessor.java:94)
    at org.springframework.boot.context.properties.ConfigurationPropertiesNativeConfigurationProcessor$TypeProcessor.handleJavaBeanProperties(ConfigurationPropertiesNativeConfigurationProcessor.java:159)
    at org.springframework.boot.context.properties.ConfigurationPropertiesNativeConfigurationProcessor$TypeProcessor.process(ConfigurationPropertiesNativeConfigurationProcessor.java:112)
    at org.springframework.boot.context.properties.ConfigurationPropertiesNativeConfigurationProcessor$TypeProcessor.process(ConfigurationPropertiesNativeConfigurationProcessor.java:94)
    at org.springframework.boot.context.properties.ConfigurationPropertiesNativeConfigurationProcessor.processConfigurationProperties(ConfigurationPropertiesNativeConfigurationProcessor.java:70)
    at org.springframework.boot.context.properties.ConfigurationPropertiesNativeConfigurationProcessor.process(ConfigurationPropertiesNativeConfigurationProcessor.java:64)
    at org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.NativeConfigurationRegistrar.lambda$processBeanFactory$0(NativeConfigurationRegistrar.java:55)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.NativeConfigurationRegistrar.processBeanFactory(NativeConfigurationRegistrar.java:55)
    at org.springframework.aot.context.bootstrap.generator.ApplicationContextAotProcessor.bootstrapMethod(ApplicationContextAotProcessor.java:107)
    at org.springframework.aot.context.bootstrap.generator.ApplicationContextAotProcessor.process(ApplicationContextAotProcessor.java:95)
    at org.springframework.aot.build.ContextBootstrapContributor.contribute(ContextBootstrapContributor.java:80)
    at org.springframework.aot.build.BootstrapCodeGenerator.generate(BootstrapCodeGenerator.java:91)
    at org.springframework.aot.build.BootstrapCodeGenerator.generate(BootstrapCodeGenerator.java:71)
    at org.springframework.aot.build.GenerateBootstrapCommand.call(GenerateBootstrapCommand.java:107)
    at org.springframework.aot.build.GenerateBootstrapCommand.call(GenerateBootstrapCommand.java:42)
    at picocli.CommandLine.executeUserObject(CommandLine.java:1953)
    at picocli.CommandLine.access$1300(CommandLine.java:145)
    at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2352)
    at picocli.CommandLine$RunLast.handle(CommandLine.java:2346)
    at picocli.CommandLine$RunLast.handle(CommandLine.java:2311)
    at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2179)
    at picocli.CommandLine.execute(CommandLine.java:2078)
    at org.springframework.aot.build.GenerateBootstrapCommand.main(GenerateBootstrapCommand.java:112)

Debugging shows it's coming from the com.ecwid.consul.v1.Response class which has a generic field and a getter that is returning type T, causing its property type to be ? which then resolves to null:

public final class Response<T> {
    private final T value;

    public T getValue() {
       return value;
    }
}

This leads to the general case, where the NPE can be reproduced with any generic object as a field in a @ConfigurationProperties bean:

@ConfigurationProperties(prefix = "example")
public class DemoProperties {
    private GenericObject<?> generic;

    public GenericObject<?> getGeneric() {
        return generic;
    }

    public static final class GenericObject<T> {
        private final T value;

        public GenericObject(T value) {
            this.value = value;
        }

        public T getValue() {
            return value;
        }
    }
}

Environment:

  • Java 11
  • Spring Boot 2.6.1
  • Spring Native / Spring AOT 0.11.0
@nbruno nbruno changed the title NPE during AOT generation when @ConfigurationProperties contains ConsulClient property NPE during AOT generation when @ConfigurationProperties contains generic property Dec 21, 2021
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Dec 21, 2021
@snicoll
Copy link
Contributor

snicoll commented Dec 22, 2021

Thanks for the detailed report. This is related to #1252, we shouldn't call resolve() there but rather toClass().

@snicoll snicoll added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Dec 22, 2021
@snicoll snicoll added this to the 0.11.2 milestone Dec 22, 2021
@snicoll snicoll self-assigned this Jan 5, 2022
@snicoll snicoll closed this as completed in f2f09f2 Jan 5, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
type: bug A general bug
Development

No branches or pull requests

3 participants