javaspringspring-bootintellij-ideaconfigurationproperties

Is it possible to make Spring Boot Configuration Processor work correctly with maps which values are complex structures (in Intellij IDEA)?


Source code that reproduces the problem: link.

Suppose I have this kind of structure of configuration properties:

    @Data
    @ConfigurationProperties(prefix = "props")
    public class ConfigProperties {
    
        private String testString;
        private Map<String, InnerConfigProperties> testMap;
    }
    @Data
    public class InnerConfigProperties {
    
        private String innerString;
        private Integer innerInt;
    }

In application.yml I set them in this way:

props:
  testString: asdadasd
  somWrongProperty: asdasd
  testMap:
    key1:
      innerString: value1
      innerInt: 1
      someInnerWrongProperty: wrongvalue
    key2:
      innerString: value2
      innerInt: 2

After launching annotation processing only the simple properties work correctly (you can navigate to their declaration by clicking with ctrl, also autocomplete for them works). Also, IDEA detects if the property is incorrect and highlights it.

For nested structures (which are map values) both of these features don't seem to work properly. You still can click on them but IDEA will navigate to the map declaration. Also, code completion for map values and highlighting of the wrong fields don't work.

Screenshot from IDEA:

enter image description here

Does anybody know how to make it work correctly? Feel free to use the attached example code.

Thanks in advance.

UPDATE

Seems to be fixed in Intellij IDEA 2022.1. Related issues: IDEA-151708 and IDEA-159276.

Nice bugfix productivity though.


Solution

  • I believe you're asking about the added

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    

    This is basically an annotation processor - a special hook into compilation process that can detect classes annotated with some annotation during compile time and generate some resources based on that definition. Some annotation processor generate other source files, this one however introspects the classes annotated with @ConfigurationProperties by reflection and based on the field names and types found in this classes it generates a special json file (META-INF/spring-configuration-metadata.json in the target build directory).

    You can open it up and see how does it look like.

    Now a couple of notes on this process:

    1. Since it happens during the compilation - it doesn't look at application.yaml
    2. The generated JSON in general is not used by spring boot itself during the runtime but intended for IDEs so that they could build some nifty integrations. That's what IntelliJ basically does.

    Now, IntelliJ (Only Ultimate Edition, since community edition doesn't include any integration with spring) can indeed read this file, and provide some autocompletion features.

    But Based on the information provided in the configuration properties that include Maps an annotation processor (that again runs during the compilation and has an access to the class only) merely cannot generate correct values of keys for example. So IntelliJ won't offer you to chose from key1, key2, since they do not exist in the configuration properties java files. That's why it doesn't work. Bottom Line, IntelliJ is not guilty, it does the best it can :)

    In terms of resolution:

    There are two paths you can try:

    1. Instead of using Strings as keys, use an enum. Since it will have a finite and well defined set of values, probably the annotation processor will generate a better json (if it doesn't - its a bug or, rather a request for enhancement, in the annotation processor)

    2. Assuming, that the annotation processor does its best job, but not always succeeds, you can define the json manually as described in Spring Boot Documentation