How to configure for Spring Boot Configuration Annotation Processor using #ConfigurationProperties on IntelliJ? - spring

On IntelliJ, I am getting a Spring Boot Configuration Annotation Processor not configured for having #ConfigurationProperties. Below is my class:
#Configuration
#ConfigurationProperties(prefix = "abc")
#Data
#RefreshScope
class Config {
String propA;
String propB;
...
}
I am not sure what's causing this and when I click on the wrench for settings, I do not see any options to configure for metadata files.

I faced the same problem with IntelliJ IDEA 2020.2 and Maven 3.6.2. The solution was to explicitly set the annotation processor in the maven-compiler-plugin settings. I found the answer here:
https://stackoverflow.com/a/48028193/9989732
https://stackoverflow.com/a/64031211/9989732
The full configuration:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.4.2</version>
<optional>true</optional>
</dependency>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<annotationProcessorPaths>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.4.2</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>

I resolved it by adding the following dependency to my pom file
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.2.6.RELEASE</version>
<optional>true</optional>
</dependency>

You can easily generate your own configuration meta-data file from items annotated with #ConfigurationProperties by using the spring-boot-configuration-processor jar. The jar includes a Java annotation processor which is invoked as your project is compiled. To use the processor, simply include spring-boot-configuration-processor as an optional dependency, for example with Maven you would add:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

For Gradle, like Maven, we need to add The appropriate annotation processor. To do so, add a line to the dependencies section in your build.gradle file.
dependencies {
...
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor:'
...
}

Related

Why i have to add exclusion in spring-boot-maven-plugin while using LOMBOK?

I am trying to use Lombok in my project. My question is that I have to add Lombok dependency in POM.xml as below
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
BUT
a) WHY DO I have to add the code below under the build tag? What is the need for the below exclusion?
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
b) Why do I need to install the LOMBOK plugin as part of IntelliJ idea settings?
Can anyone explain in simple and layman's language so that my basics are cleared?
a) Lombok is an annotation processor and is only needed at compile time. That's why it is excluded.
This configuration explicitly removes Lombox from the target artifact.
b) IntelliJ does not use Maven to compile your code. In order to process the Lombok annotations, the IntelliJ plugin must be activated.
IntelliJ uses an internal mechanism to compile your code.
c) Lombok generates code from the annotations. For example
#Getter
public class Employee() {
private String name;
}
will generate String getName() at COMPILE time.
Therefore Lombok is not needed at runtime.

Maven: Can I use a version from dependency management in annotationProcessorPath?

I'm importing a shared "bill of materials" (bom) in my dependencyManagement, like this:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>common-bom</artifactId>
<version>1.2.3</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
That common-bom defines versions, and then I just use whatever version it defines, like this:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
That's all working great, except that I also have this
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths combine.children="append">
<annotationProcessorPath>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</plugin>
So now I anyway need to specify a lombok version, not for the actual dependency, but for the annotation processor path. Is there a way I can somehow use the same value? Can it for example be stored as a property in the common-bom?
This is not possible because maven-compiler-plugin does not currently follow dependencyManagement rules (MCOMPILER-391, go vote for it!).
The only thing you can do for now it seems is to declare a lombok.version property in the parent pom, and use that in your annotationProcessorPath declaration.
(note that Spring Boot already defines such a property for Lombok)

Spring boot - binding properties [Configuration properties]

I work on spring boot version: 2.0.2.RELEASE. In my application.yml I have:
cars:
color-to-brands:
red: car1, car2
blue: car3, car4
and my config class looks like this:
#Getter #Setter
#Configuration
#ConfigurationProperties(prefix = "cars")
public class CarsProperties {
private Map<String, List<String>> colorToBrands = Collections.emptyMap();
}
When I start the app, I'm keep getting:
Failed to bind properties under 'cars.color-to-brands' to
java.util.Map>:
Reason: Failed to bind properties under 'cars.color-to-brands' to java.util.Map<java.lang.String, java.util.List<java.lang.String>>
Action:
Update your application's configuration
Now, to summarize what I have already done to fix it:
According to documentation I have added a dependency that gives
me annotation processor for my #ConfigurationProperties:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
<optional>true</optional>
</dependency>
I have annotation processor enabled. I'm using Intellij. Annotation processors -> Maven default annotation processors profile has ticked Enable annotation processing, Processor path: contains (...)\.m2\repository\org\springframework\boot\spring-boot-configuration-processor\2.0.2.RELEASE\spring-boot-configuration-processor-2.0.2.RELEASE.jar, Store generated sources relative to: Module content root,
In the pom file I've added path for this processor (among others I
use):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<compilerArg>
-Amapstruct.defaultComponentModel=spring
</compilerArg>
</compilerArgs>
</configuration>
In addition, intellij keep showing me a popup inside the CarsProperties:
Re-run Spring Boot Configuration Annotation Processor to update
generated metadata
I've skipped #EnableConfigurationProperties as:
Spring Boot documentation says, every project automatically includes
#EnableConfigurationProperties.
Somewhere in between I also did: Reimport All Maven Projects, clean install, Rebuild project, and Invalid Caches and Restart
I'm sitting in front of that computer for few hours now, Can't get it done. What am I doing wrong ? Why it doesn't want to work ?
Updated spring boot version to 2.1.6.RELEASE and it's fixed

Transitive Dependency: Using Elasticsearch Rest High Client problem in AEM

I am trying to use Java High Level Rest Client in Adobe Experience Manager to finish project of comparison between Lucene, Solr and Elasticsearch search engines.
I am having some problems with elasticsearh implementation.
Here is the code:
Dependency in the parent pom.xml (the same is defined in core pom.xml)
<!-- Elasticseach dependencies -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.4.0</version>
</dependency>
The only line of code that I am using that is from dependencies above
try (RestHighLevelClient client = new
RestHighLevelClient(RestClient.builder(new HttpHost(server, port,
protocol),
new HttpHost(server, secondPort, protocol)));)
{
}
catch (ElasticsearchException e)
{
LOG.error("Exception: " + e);
}
protocol = "http", server = "localhost", port = 9200, secondPort =
9201
Error
Dependencies from IntelliJ
I know that there is usually problem with dependencies versions, but all are 7.4.0 in this case. Also elasticsearch 7.4.0v is running locally on 3 nodes.
This project is done on We.Retail project so it is easy to replicate. Also all the code with this error is available here:
https://github.com/tadijam64/search-engines-comparison-on-we-retail/tree/elasticsearch-integration
AEM 6.4v.
Any info or idea is appreciated.
UPDATE
I tried with adding the following to embed these dependencies externally since they are not OSGi dependencies:
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Embed-Dependency>org.apache.servicemix.bundles.solr-solrj, log4j, noggit, zookeeper,
elasticsearch-rest-high-level-client
</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive>
<Embed-Directory>OSGI-INF/lib</Embed-Directory>
<Export-Package>we.retail.core.model*</Export-Package>
<Import-Package>
*;resolution:=optional
</Import-Package>
<Private-Package>we.retail.core*</Private-Package>
<Sling-Model-Packages>
we.retail.core.model
</Sling-Model-Packages>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
The error remains. I also tried adding it to the "export-package", but nothing helps.
And by Elasticsearch documentation, all I need to use Elasticsearch is
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.4.0</version>
</dependency>
but then NoClassDefFoundErrors occurs. It seems like a problem with transitive dependencies maybe. Not sure, but any idea is appreciated.
Some other suggestions can be found here: https://forums.adobe.com/thread/2653586
I have also tried adding it's transitive dependencies like org.elasticsearch and org.elasticsearch.client, but it does not work. The same error, just other class.
AEM version 6.4, Java version: jdk1.8.0_191.jdk
So my guess was right, transitive dependencies were not included altho <Embed-Transitive>true</Embed-Transitive> exists.
The following is necessary when running elasticsearch as a search engine on AEM the problem:
I have added all transitive dependencies in pom.xml (versions are defined in parent/pom.xml):
<!-- Elasticsearch -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch-x-content</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>rank-eval-client</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-imaging</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>lang-mustache-client</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
</dependency>
It is important to add all third-party dependencies as <Embed-Dependency> inside maven-bundle-plugin like this:
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Embed-Dependency>org.apache.servicemix.bundles.solr-solrj, noggit,
elasticsearch-rest-high-level-client,
elasticsearch,
elasticsearch-rest-client,
elasticsearch-x-content,
elasticsearch-core,
rank-eval-client,
lang-mustache-client,
httpasyncclient;
</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive>
<Embed-Directory>OSGI-INF/lib</Embed-Directory>
<Export-Package>we.retail.core.model*</Export-Package>
<Import-Package>
*;resolution:=optional
</Import-Package>
<Private-Package>
we.retail.core*
</Private-Package>
<Sling-Model-Packages>
we.retail.core.model
</Sling-Model-Packages>
<_fixupmessages>"Classes found in the wrong directory";is:=warning</_fixupmessages>
</instructions>
</configuration>
</plugin>
Important to notice:
All third-party dependencies (the ones outside of OSGi) must be included in the "Embed-Dependency"
"Embed-Transitive" must be set to true to include transitive dependencies
"Import-Package" must include "*;resolution:=optional" to exclude all dependencies that could not be resolved so that the program can run
normally
For some reason, there was an error in compile time when "elasticsearch" dependency was added which is not important for this
task, so I've decided to ignore it this way:
<_fixupmessages>"Classes found in the wrong directory";is:=warning</_fixupmessages>
Though challenging, I finally resolved it. There are many similar or the same problems on Google, so I hope this will help someone. Thanks to everyone that tried to help.

spring-boot-configuration-processor is not working on maven submodule project

I have a maven multi module project with one parent and three child modules.
The application uses spring boot. In one of the child modules, I have the SpringBootApplication:
#SpringBootApplication
#EnableConfigurationProperties({AppProperties.class})
public class MainSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(MainSpringBootApplication.class, args);
}
}
The App Properties are in the same module:
#Data
#ConfigurationProperties(prefix = "asdf")
public class AppProperties {
...
}
In the pom.xml of that module there is a dependency for the spring-boot-configuration-processor:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
Now the problem is, when I run mvn install on the parent project, the target/classes/META-INF/spring-configuration-metadata.json
file within this child module is not created. When I modify the pom of that child module to directly inherit from:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
and do mvn install directly on the child module, the target/classes/META-INF/spring-configuration-metadata.json file is generated.
Do you have any hints?
There are two options I am aware of.
First one is my favourite (especially because it configures the order of APT libraries - the order of code generation).
But based, say, on the IDE auto-discovery mechanism, the 2nd one is also a good bet.
Both ones are primarily targeting the minimum size of the final artefact (dependencies' scope), which, for me is very important.
Not to increase the deliverable/archetype size with useless dependencies (apt libraries are needed only at compile time) is very important in the era of k8s/docker/cloud (resource efficiency).
So, without further ado, the options:
Use APT libraries only in maven compiler plugin configuration (nothing in dependencies).
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
This option is useful for the case the maven-compiler-plugin is not configured in plugins/pluginsManagement (but probably by means of its properties).
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
Notes:
For option 2, scope provided is important, because it will allow to use the APT during the compilation but won't be included in the final artefact).
On the other hand (back to your question), in order to generate documentation in target/classes/META-INF/spring-configuration-metadata.json from the java doc, for lombok based java classes, you need these as well (#Getter and #Setter - are both needed).
#Setter
#Getter
#ConfigurationProperties(prefix = "asdf")
public class AppProperties {
/**
* foo - Should not be null or empty.
*/
private Map<String, String> foo;
and the following maven compiler plugin configuration as property (or in the plugin configuration).
<maven.compiler.parameters>true</maven.compiler.parameters>
After the compilation the IDE will parse the spring-configuration-metadata.json file and offer suggestion/quick doc/autocomplete in application.properties/application.yml.
Kr
I explicitly added:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.1.5.RELEASE</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</plugin>
to the plugins section of the pom of the child module containing the #ConfigurationProperties annotated class. Now target/classes/META-INF/spring-configuration-metadata.json is generated.

Resources