How to get Intellij to recognize properties in application.yml - spring-boot

I am trying to get Intellij to recognize my properties using gradle. I have followed the steps here. So this means I have a #ConfigurationProperties annotated class with some properties.
I added the spring dependency to process them:
dependencies {
optional "org.springframework.boot:spring-boot-configuration-processor"
}
compileJava.dependsOn(processResources)
I added the plugin (I've tried not using the plugin and just making it a compile dependency, no change)
buildscript {
repositories {
maven { url 'http://repo.spring.io/plugins-release' }
}
dependencies { classpath 'io.spring.gradle:propdeps-plugin:0.0.9.RELEASE' }
}
apply plugin: 'propdeps'
apply plugin: 'propdeps-maven'
apply plugin: 'propdeps-idea'
When I run the build, I see a build/classes/java/main/META-INF/spring-configuration-metadata.json file is created based off of my properties.
When I try to use the property in either application.yml or application.properties, Intellij says it cannot resolve it.
The docs does say it should be called additional-spring-configuration-metadata.json and may expect it to be called that to process it, but I do not see a way to make the build name it that way nor configure Intellij to expect otherwise.
Has anyone got this working with gradle? Or is this a bug.
Edit I created a repo with a pair of projects to demonstrate this. One for gradle and one for maven. I created the projects from start.spring.io and basically just added the properties configuration. I also used a straight compile dependency in both cases instead of optional / compileOnly.
I had not confirmed this before, but the code assist does work for maven, but not gradle. Both create a spring-configuration-metadata.json in the META-INF in their respective build folders. I am not exactly sure who is not picking it up.
Misc relevant versions
Intellij: 2017.3.4
Springboot: 1.5.9
Gradle: 4.4.1
Java: 8.161

Turn the annotation processing on
Do not delegate IDE build/run actions to Gradle
Rebuild your project in IDE: Build -> Rebuild Project

As far as I can tell, IntelliJ (at the time of this writing, 2018.1.2) wants the spring-configuration-metadata.json file to either be in a main source root (src/main/resources/META-INF/ or src/main/java/META-INF/) or in its default output directory for it to pick it up for autocompletion of properties in your source tree. To expand on phospodka's comment, you can add something like this to your build.gradle to satisfy IntelliJ.
task copyConfigurationMetadata(type: Copy) {
from(compileJava) {
include 'META-INF/spring-configuration-metadata.json'
}
into "out/production/classes"
}
compileJava {
dependsOn processResources
finalizedBy copyConfigurationMetadata
}

This answer is a combination of the (at this time) other two answers with a minor twist. In my case this is what "fixed" the issue: (in 2019.03.01-Ultimate)
Turn on the default annotation processing (File>Settings>Build, Execution, Deployment>Annotation Processors>Enable Annotation processing
Select Obtain processors from project classpath
Select Store generated sources relative to module output directory
keep other defaults
click OK
Add the code in #thyme's answer to your build.gradle
EXCEPT instead of into "out/production/classes"
use: into "build/generated/sources/annotationProcessor"
Now you should be able to run gradle clean/build and Intellij should be able to find your "additional metadata" definitions.
Notice that even though the build.gradle code doesn't explicitly mention 'additional-spring-configuration-metadata.json', it is exactly that "additional metadata" that ends up in the annotationProcessor folder as "spring-configuration-metatdata.json" where Intellij finds it.
EDIT: Also note, you need to clean / rebuild after adding any new "additional metadata" items before Intellij will see the new entries (in the freshly regenerated file).

Related

IntelliJ won't import modules from gradle composite builds

UPDATE: Not only is IntelliJ having trouble, but the reason seems to be because my setup fails to build in Gradle. Still unsure why.
I'm trying to set intellij up to recognize composite gradle builds. I have Project A which depends on Project B, like this:
/p/projecta
/p/projectb
I've tried MANY things, but IntelliJ can't find the declarations of anything in project-b that I try to access from project-a. For example, in ProjectA.java below, IntelliJ marks the import for Project B as Cannot resolve symbol ProjectB
// projecta/src/main/java/projecta/ProjectA.java
import projectb.ProjectB; // 'Cannot resolve symbol ProjectB'
// projectb/src/main/java/projectb/ProjectB.java
public class ProjectB {
}
// projecta/settings.gradle
rootProject.name = 'projecta'
includeBuild '../projectb'
// projectb/settings.gradle
rootProject.name = 'projectb'
Despite the above configuration, it does not work. IntelliJ continues to mark all symbols from Project B as not resolvable.
Other things I've tried
removing the includeBuild from settings.gradle, and right clicking in the gradle window on Project A, going to 'Composite Build Configuration' and adding Project B from there. Same issue.
Adding this code to build.gradle in Project A
tasks.register('run') {
dependsOn gradle.includedBuild('projectb').task(':run')
}
Putting Project B inside of Project A on the disk: /p/projecta/projectb and then changing includeBuild in projecta/settings.gradle to includeBuild 'projectb'
Many variations of #2 to try to get IntelliJ to recognize the gradle dependency.
I recently ran into this problem and figured it out so I wanted to respond here so others can benefit from my foraging through the jungle of parameters and trial and error.
I have the exact same project set up as described in the question. Using Gradle 5.0, Intellij was able to correctly import and link my sources and I was able to build correctly on the command line. When I bumped the Gradle version to 5.6 and higher, Intellij was no longer able to link the sources correctly. Re-importing my project would actually work but the dependency that represents the included build would be highlighted red and the console would say that it couldn't resolve it. This happened for every Gradle version after 5.6.
It seems the root cause was Intellij was using Java 11 for Gradle while I had sourceCompatibility set to 10. It looks like this breaks things in more recent versions of Gradle (understandably).
I was also able to fix this by adding the following to my project's build.gradle
java {
disableAutoTargetJvm()
}
However, I just updated my JDK for Gradle in Intellij to be Java 10 and everything worked....
My problem was just like for #Troy, had to make all projects work under the same JDK by adding this to the build.gradle.kts:
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(8))
}
}

Why do I get UnknownPluginException when trying to use a custom Kotlin complier plugin in Gradle?

I have created a custom Kotlin compiler plugin for Gradle. It was inspired by kotlin-allopen (2) and sample-kotlin-compiler-plugin, and is supposed to make all Kotlin classes non-final.
The problem is, I'm unable to use it in my projects, I only get the following:
Caused by: org.gradle.api.plugins.UnknownPluginException: Plugin with id 'no.synth.kotlin.plugins.kotlin-really-allopen' not found.
at org.gradle.api.internal.plugins.DefaultPluginManager.apply(DefaultPluginManager.java:131)
I have tried both the "new" plugin syntax:
plugins {
id "no.synth.kotlin.plugins.kotlin-really-allopen" version "0.1"
}
.. and the old one:
buildscript {
repositories {
mavenLocal()
}
dependencies {
classpath "no.synth.kotlin.plugins:kotlin-really-allopen:0.1"
}
}
apply plugin: "kotlin-really-allopen" // I've tried "no.synth.kotlin.plugins.kotlin-really-allopen" as well
So what am I doing wrong? Here's the plugin: https://github.com/henrik242/kotlin-really-allopen
EDIT: I have updated the repository with an example app and a README.md to easily reproduce the problem.
Your Gradle plugin doesn't seem to contain any entry under META-INF/gradle-plugins.
Gradle requires that every plugin ID is mapped to the implementation class, and this mapping is stored in META-INF/gradle-plugins resources.
To map the plugin ID kotlin-really-allopen, you would need a resource file
src/main/resources/META-INF/gradle-plugins/kotlin-really-allopen.properties.
See: Wiring for a custom plugin
You can also use the Gradle Plugin Development Plugin, which automatically generates these entries from the build script DSL.
Also, your repository doesn't seem to contain an actual Gradle plugin implementation, there's only the part that the compiler needs to load. For an example that contains the Gradle part too, take a look at kevinmost/debuglog.
Move apply plugin: "kotlin-really-allopen" in your build.gradle module app on top

Load gradle plugin from sibling folder

I've started to create a Gradle plugin. The build is finishing and producing a valid plugin jar (I think), but the implementation is skeletal. I have a couple of unit tests, but I want to have a very simple way to "system test" the plugin.
The original plugin is in my Eclipse workspace. I want to create a second Eclipse standalone project with a build.gradle that references the jar produced by the other project, just using a relative path to the jar in the other project's "build" folder.
My first stab at this is:
buildscript {
repositories {
jcenter()
mavenCentral()
flatDir {
dirs "../GradleYangPlugin/build/libs"
}
}
dependencies {
classpath files("GradleYangPlugin-1.0.0-SNAPSHOT.jar")
}
}
apply plugin:"com.att.opnfv.yang.gradle"
I then just tried "gradle tasks" to see what it said. It fails with "Plugin with id 'com.att.opnfv.yang.gradle' not found."
You might ask whether I constructed the plugin jar correctly. That's a valid question, but I can show that's not even relevant yet. I ran a File IO monitor (SysInternals ProcessMonitor) while I ran the build, looking for any occurrences of "GradleYangPlugin-1.0.0-SNAPSHOT.jar". The only place it looked for it was in the current directory (the root directory of the second project). This shows that the syntax I used for my "flatDir" element isn't groked by Gradle, and it's also not complaining about it. It just ignores it, seemingly.

Spring Boot + Spring-Loaded (IntelliJ, Gradle)

I'd like to use hot swap with my Spring Boot project. Somehow I am not able to make it working by running it in my IDE (IntelliJ), despite of having this topic covered by documentation. I simply run the class with my main method with VM attributes:
-javaagent:/path/to/jar/springloaded.jar -noverify
My question is, how do I make it work? :-)
Further question is how to use spring loaded with Gradle and IntelliJ. I find it quite inconvenient to force the developer to download the JAR manually, place it somewhere and point to it with a JVM parameter. Is there any better way (should I configure my own task which does the job and run it from my IDE as a Gradle task)?
You need to configure the project as stated in the documentation:
http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#howto-reload-springloaded-gradle-and-intellij-idea
After that, you must configure your IDE to output the compiled classes in build/classes/main (with Idea plugin, you can configure the outputDir as specified in the above link, and then invoke gradle idea to have it done).
Then, if you launch the task (run / bootRun) or run the main class from the IDE's using the debug mode, hot code reloading should work when a class is compiled.
The gotcha here is that IntelliJ, unlike Eclipse, doesn't automatically compile a class when it is saved (even if you configure the compiler to "Build on save", it won't do it when is Running/Debugging). This is apparently a design decission made by IntelliJ - as stated here Intellij IDEA Java classes not auto compiling on save (CrazyCoder answer) .
It would be ideal if spring boot provided a configuration option to monitor your source code files and recompile them when they change - that is what Grails does. But I think such a think does not exist yet, and maybe is not even possible to combine that with gradle, which is the responsible of managing the classpath and that kind of things.
So there are two options as far as I can tell:
You remember to compile everything you edit (adding an easier Compile shortcut as suggested in the previous StackOverflow link might help).
You put some filesystem monitor (inotify-tools for Linux, launchd for Mac OS X are examples) that invokes gradle compileJava/compileGroovy when a change is detected in any source code file.
First is tedious, second is slow :) . Actually there's another option: you change your IDE :-D (or install the EclipseMode IntelliJ plugin).
If one wants to be able to run the application solely from IntelliJ (using Right Click -> Debug on the main method) and not involve Spring Boot's Gradle tasks at all, you simply need to do the following:
Configure the run configuration in IntelliJ to use the SpringLoaded agent. This is easy to do and an example is shown in the following screenshot:
Notice how I have added a VM Option: -javaagent:/path/to/springloaded-${version}.jar -noverify (which you can download here)
Debug using Right Click -> Debug like the following screenshot:
Everytime you make a change and want to reload it, just compile the project. The default shortcut is Cntrl+F9, but you can also access it from the menu Build -> Make Project
I managed to do this with IDEA in a Maven project, it should work with the Gradle version as well I guess, my procedure was the following.
Settings -> Compiler -> Make project automatically (only works while not running/debugging !)
Start the project with the sprint-boot-plugin outside of the IDE (a trick because of the above sentence).
The Maven plugins setup looks like the following:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.0.RELEASE</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
Now change some code and reload the page.
I'm running SpringBoot and Gradle in IntelliJ Idea. Auto-reloading is working 100%
Static Content is autoreloading (instantly)
Thymeleaf is autoreloading (instantly)
Controllers / Java Files require me to hit the "build" button (takes a few seconds), but does not require a restart - it's just to compile the files, so Spring Loaded can pick them up.
Step 1: Get SpringLoaded going
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:1.2.1.RELEASE"
classpath 'org.springframework:springloaded:1.2.1.RELEASE'
}
}
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'idea'
apply plugin: 'spring-boot'
repositories {
jcenter()
mavenLocal()
mavenCentral()
}
mainClassName = 'com.noxgroup.nitro.NitroApp'
idea {
module {
inheritOutputDirs = false
outputDir = file("$buildDir/classes/main/")
}
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web:1.2.1.RELEASE")
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
}
jar {
baseName = 'org.noxgroup-nitro'
version = '0.1.0'
}
task wrapper(type: Wrapper) {
gradleVersion = '1.11'
}
Step 2: Create an Application.properties
And add the following:
spring.thymeleaf.cache=false
Step 3: Run the bootRun task
(Not just the standard run task - this adds SpringLoaded functionality)
Step 4: Compile your Java
Make your Java files by hitting "Make Project" or pressing "Ctrl/Command + F9
In later versions of gradle you can start a command window and run
gradle -t classes
This will start a process that look for changes to source code and recompile them.
In another run.
gradle bootRun
Any changes to java or groovy src will automatically be recomplied. While not intellij specific, your good to go with intellij. You could even make do with you favorite text editor (e.g. submlime, atom ).
credits/link

Gradle multiproject gives "Could not find property 'sourceSets' on project" error

I had quite good gradle configuration, that built everything just fine. But one of the projects of my multi-project build derived from the rest of them so much, that I would gladly move it to another git repo and configure submodules to handle it.
First, I moved Project and its resources to subfolder Libraries/MovedProject. After altering some lines in gradle configurations it worked fine. But then I decided to write a new build.gradle just for this project, and move all configurations there from the main one.
And this is where everything stopped working. When I try to call any task it always ends
with Could not find property 'sourceSets' on project ':Libraries/MovedProject'. Line which is responsible for it is:
dependencies {
...
if (noEclipseTask) {
testCompile project(':Libraries/MovedLibrary').sourceSets.test.output
}
}
which I use for running tests in which I use classes from other projects. If I remove that line, the build fails only when it reaches compileTestJava task of projects that make use of MovedProject. If I remove that line and call gradle :Libraries/MovedLibrary:properties I can see :
...
sourceCompatibility: 1.7
sourceSets: [source set main, source set test]
standardOutputCapture: org.gradle.logging.internal.DefaultLoggingManager#1e263938
...
while gradle :Libraries/MovedLibrary:build builds correctly.
Currently I've got everything set up as following:
directories:
/SomeMainProject1
/SomeMainProject2
/SomeMainProject3
/Libraries
/MovedProject
build.gradle
dependencies.gradle
project.gradle
tasks.gradle
/Builder
dependencies.gradle
project.gradle
tasks.gradle
build.gradle
settings.gradle
settings.gradle
include Libraries/MovedProject,
SomeMainProject1,
SomeMainProject2,
SomeMainProject3
sourceSets for MovedProject are defined in Libraries/MovedProject/project.gradle:
sourceSets {
main {
java {
srcDir 'src'
srcDir 'resources'
}
resources { srcDir 'resources' }
}
test { java {
srcDir 'test/unit'
} }
}
dependencies that makes use of sourceSets.test.output are stored in Builder/dependancies.gradle, and set for each project that needs MovedProject to run tests:
project(':SomeMainProject1') {
dependencies {
...
if (noEclipseTask) {
testCompile project(':Libraries/net.jsdpu').sourceSets.test.output
}
}
}
What would be the easiest way to get rid of that error and make gradle build projects with current directory structure? I would like to understand why gradle cannot see that property.
The line in question is problematic because it makes the assumption that project :Libraries/MovedLibrary is evaluated (not executed) before the current project, which may not be the case. And if it's not, the source sets of the other project will not have been configured yet. (There won't even be a sourceSets property because the java-base plugin hasn't been applied yet.)
In general, it's best not to reach out into project models of other projects, especially if they aren't children of the current project. In the case of project A using project B's test code, the recommended solution is to have project B expose a test Jar (via an artifacts {} block) that is then consumed by project A.
If you want to keep things as they are, you may be able to work around the problem by using gradle.projectsEvaluated {} or project.evaluationDependsOn(). See the Gradle Build Language Reference for more information.
I had a similar error happen to me in a multimodule project, but for me the cause was as simple as I had forgotten to apply the java-library plugin within the configurations, I only had maven-publish plugin in use.
Once I added the plugin, sourceSets was found normally:
configure(subprojects) {
apply plugin: 'maven-publish'
apply plugin: 'java-library'
....

Resources