Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 347
amseager Avatar asked Dec 20 '19 14:12

amseager


People also ask

Is it possible to add any configuration to spring boot?

Spring Boot lets you externalize your configuration so that you can work with the same application code in different environments. You can use properties files, YAML files, environment variables, and command-line arguments to externalize configuration.

What is the use of spring boot configuration processor?

The configuration processor scans for classes and methods with this annotation to access the configuration parameters and generate configuration metadata.


2 Answers

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

like image 100
Mark Bramnik Avatar answered Oct 24 '22 13:10

Mark Bramnik


According to current documentation for auto-completing-code, there is no such way that IntelliJ IDEA will suggest you the next possible key and will notify you for incorrect value such as somWrongProperty or someInnerWrongProperty

What I found somewhat related and useful for the above use-case is Expand a string at caret to an existing word

  • Press Alt+/ or choose Code | Completion | Cyclic Expand Word to search for matching words before the caret.

  • Press Shift+Alt+/ or choose Code | Completion | Cyclic Expand Word (Backward) to search for matching words after the caret and in other open files.

enter image description here


Code Style. YAML We can customize the code style for YAML as following but however there is no option for auto-complete and error for above use-case

File | Settings | Editor | Code Style | YAML for Windows and Linux
IntelliJ IDEA | Preferences | Editor | Code Style | YAML for macOS Ctrl+Alt+S


Plugins

Further, I have gone through the plugins to achieve the use-case and there are some useful plugins that convert properties to yaml but nothing related to use-case. You might need to wait or create similar kinds of the plugin. You might find this helpful

enter image description here

like image 40
Romil Patel Avatar answered Oct 24 '22 14:10

Romil Patel