IntelliJ is using unexpected source directory from annotation processing output - gradle

I have a Gradle project that has some annotation processing involved (this time Mapstruct)
If I don't have any additional source directories IntelliJ is generating the classes in src/main/generated
As soon as I add an additional source directory e.g.
sourceSets.main.java.srcDir { "${project.buildDir}/generated-src/1" }
then IntelliJ starts to generate the annotation processor classes in that directory build/generated-src/1. Interestingly if I have additional source locations it takes the first one alphabetically.
Note that I'm using the Build and run using IntelliJ IDEA build option under Settings > Build, Execution, Deployment > Build Toosl > Gradle
Example project is available here: https://github.com/tkgregory/gradle-src-directory-issue.git
Is this the expected behaviour? When combinging Jooq + Mapstruct I'm getting Mapstruct classes generated under a source directory added by the Jooq plugin.

Related

Could not get unknown property 'a.b.c' for root project

I got some source code and was asked to build it. It was a Gradle project. So I changed to the project directory and ran:
$ gradle clean assemble
and the following error came up:
...
* What went wrong:
A problem occurred evaluating root project 'pcase'.
> Could not get unknown property 'postgresql.jdbc' for root project 'pcase' of type org.gradle.api.Project.
...
There is a settings.gradle file in the project folder too. It contains:
rootProject.name = 'pcase'
I took a look at build.gradle and found lots of occurrences like
${project['x']}
For example:
buildscript {
dependencies {
...
// FlywayDB, JOOQ.
classpath "org.postgresql:postgresql:${project['postgresql.jdbc']}"
classpath "org.flywaydb:flyway-gradle-plugin:${project['flywaydb.plugin.version']}"
classpath "nu.studer:gradle-jooq-plugin:${project['jooq.plugin.version']}"
...
What could be ${project['x']}? Looks like associative array in bash and the build script tries to get the value of the key 'x'.
But I didn't find the place in code where this array would be declared and initialized.
The question is: Is the project buildable or is it better to consult the company that worked at it before me?
From the information provided, the project is perfectly buildable, to some certain extend. First of all, project['a.b.c'] is Groovy syntax to access properties from the project object. They're referred to as project properties.
They can be set via
Project properties via command line: gradle -Ppostgresql.jdbc=x.y.z
System properties via command line: gradle -Dorg.gradle.project.postgresql.jdbc=x.y.z
System properties via gradle.properties: org.gradle.project.postgresql.jdbc=x.y.z
All 3 properties (postgresql.jdbc, flywaydb.plugin.version, jooq.plugin.version) denote the version numbers of the particular build script dependencies. However, which versions to use best is beyond my knowledge. I would certainly consult the respective project websites, Maven artifact search or simply ask the company.
org.postgresql:postgresql is the database JDBC driver and certainly depends on the database version.
org.flywaydb:flyway-gradle-plugin is for database migrations. Try with the latest version.
I wasn't able to find gradle-jooq-plugin on Maven central. It's most likely available on the Gradle Plugin Portal.

Duplicate generated class gradle output (build/...) vs intellij output (out/...)

I'm using intellij (2019.1.1) for a java gradle (5.4.1) project and use lombok (1.18.6) for autogenerating code. Intellij puts generated sources under out/production/classes/generated/... and gradle puts them under build/generated/sources/...
This is fine, and I like that intellij keeps it's own build artifacts separate from gradles, however, intellij seems to look in both directories when running projects and it complains about the duplicate generated classes.
What is the best practice for using intellij with gradle and autogenerated sources? Do you:
tell intellij to output to the same directory as gradle (this
could lead to odd behaviour if a process outside of intellij updates
a file under build/)
tell intellij to perform all tasks with
gradle (i hear this is slower than intellij's make)
tell intellij
to simply ignore the 'build' directory (how do you even do this? and
why does intellij even care about 'build/' when it knows it outputs
to 'out/')
UPDATE: to clarify the situation, the issue is NOT with lombok autogenerated code, it is with hibernate-jpamodelgen. The problem remains the same (duplicate generated sources) but I want to clarify the it is the sources generated by jpamodelgen and not lombok.
UPDATE 2: I have tried the following configuration in an attempt to tell intellij where the generated sources live and also to tell intellij to ignore the build directory. Sadly, this did not work (still get duplicate class error on the generated source files).
apply plugin: 'idea'
idea {
module {
sourceDirs += file('out/production/classes/generated')
generatedSourceDirs += file('out/production/classes/generated')
excludeDirs += file('build')
}
}
UPDATE 3:
Tried the advice from M.Riccuiti and deleted build/, out/, .idea/, .gradle/ and reimported the gradle project but intellij is still seeing the generated sources in the build/ directory.
Here is an approach that finally worked for me. The trick is to notice that when gradle generates the classes, it puts them in:
build\generated\sources\annotationProcessor\java\main\com...
but intellij has the production sources directory set to "generated" in this case, the sources go to:
build\generated\sources\annotationProcessor\java\main\generated\com...
if you compile with gradle first and then use idea, you get both of them, which causes the problem!
To solve this, replace "generated" and "generated_test" in the intellij annotation processors "production sources directory " and "test sources directory " configuration with just a "/" this makes both gradle and intellij generate the sources in the SAME directory, overwriting each other as needed. Also make sure that the "store generated sources relative to" is set to "module content root" and REBUILD the application to clear out any other sources.
The solution I proposed in previous comment was working fine in IDEA 2018.3.x but after upgrading to IDEA 2019.1 I again got this duplicate class exception...
Below is a working solution to make this work with Gradle 5.x (tested with 5.4) and IDEA 2019.1 , to implement your solution #3 which I think is the best option (do not mix gradle & idea generated output directories, and do not delegate IDEA action do Gradle )
The key point is to use excludeDirs property from idea.module extension to make IDEA ignore generated sources managed by Gradle under build/generated/sources/...
ext {
// path to Gradle generated main sources directory
gradleGeneratedMainSourcesDir = "$buildDir/generated/sources/annotationProcessor/java/main/"
// path to Gradle generated test sources directory
gradleGeneratedTestSourcesDir = "$buildDir/generated/sources/annotationProcessor/java/test/"
// path to IDEA generated sources directory
ideaGeneratedSourcesDir = "$projectDir/out/production/classes/generated"
}
idea {
module {
// exclude main & test sources generated by Gradle from project source directories
excludeDirs += file(gradleGeneratedMainSourcesDir)
excludeDirs += file(gradleGeneratedTestSourcesDir)
// include generated sources directory managed by IDEA
sourceDirs += file(ideaGeneratedSourcesDir)
generatedSourceDirs += file(ideaGeneratedSourcesDir)
}
}
See complete sample project based on this configuration here : https://github.com/mricciuti/sample-springboot-gradle-idea
You can enter to IntelliJ Settings (Preferences):
Preferences | Build, Execution, Deployment | Build Tools | Gradle | Runner
Then you tick the checkbox Delegate IDE build/run action to Gradle
Finally, you clean and build again. The issues will be resolved.

Does sonarcloud.io support groovy?

I cannot get SonarQube to scan my .groovy files on sonarcloud.io. I added the following to my build.gradle:
sonarqube {
properties {
property 'sonar.host.url', 'https://sonarcloud.io'
property 'sonar.organization', System.getenv('SONARQUBE_ORG')
property 'sonar.login', System.getenv('SONARQUBE_LOGIN')
property 'sonar.inclusions', '**/*.groovy,**/*.java'
}
}
It reports indexing 5 files, but there are 0 lines of code in sonarcloud.io.
My source is in the 'sonarqube' branch at here
My sonar cloud project is at here
Here is a project that is scanning groovy, but I can't find the source code to determine how it is configured: Link
SonarCloud does not support Groovy analysis.
The project you found is an old one, not analyzed for more than a year. It's a left-over from the former version of the service (called SonarQube.com at that time) that had some sort of support for Groovy.

How to use Afterburner.fx with Gradle instaed of Maven 3, while leaving the original project structure of afterburner.fx

afterburner.fx for JavaFX 8 is a minimalistic (3 classes) JavaFX MVP framework based on Convention over Configuration and Dependency Injection created by Adam Bien.
afterburner.fx use Maven 3.
I would like to use it with Gradle.
How to use Afterburner.fx with Gradle instaed of Maven 3, while leaving the original project structure of afterburner.fx ?
In the build.gradle File add dependencies
dependencies {
compile group: 'com.airhacks', name:'afterburner.fx', version: afterburnerfxVersion
}
In the build.gradle File add the additional Resources (.fxml , .css , .properties)
sourceSets.main.resources.srcDirs("src/main/java").includes.addAll(["**/*.fxml", "**/*.css", "**/*.properties"])
and (re-)add all the standard Resources (in the resources folder)
sourceSets.main.resources.srcDirs("src/main/resources").includes.addAll(["**/*.*"])
Update for Gradle Version 6.8.1 : if you run gradlew with --warning-mode all there is a deprecated Message:
Copying or archiving duplicate paths with the default duplicates strategy has been deprecated. This is scheduled to be removed in Gradle 7.0.
Solution
add this line:
// from https://docs.gradle.org/6.8.1/userguide/upgrading_version_5.html#implicit_duplicate_strategy_for_copy_or_archive_tasks_has_been_deprecated
// and https://docs.gradle.org/current/userguide/java_plugin.html
// Java Plugin Task processResources(type: Copy)
processResources.duplicatesStrategy = DuplicatesStrategy.INCLUDE // allow duplicates
Thanks, this helped me a lot. I added the short form of it to dependencies:
compile 'com.airhacks:afterburner.fx:1.6.0'
Additionally I added a second line to include the files from the resources folder and not only from /java. I also added **/*.png to include png files because new Image("filename.png") wasn't working anymore.
sourceSets.main.resources.srcDirs("src/main/java").includes.addAll(["**/*.fxml", "**/*.css", "**/*.properties", "**/*.png"])
sourceSets.main.resources.srcDirs("src/main/resources").includes.addAll(["**/*.fxml", "**/*.css", "**/*.properties", "**/*.png"])
I don't know why the above two lines broke the default behavior - seems like I have to add every new file type to the above lines. :/ If anyone has a better solution please tell me.

Spring Tools Suite and Gradle - Setup to use correct resources from inside STS

I have a Spring Boot Gradle project setup in Spring Tools Suite (3.7.2 RELEASE) with the following source folders:
- src/integration-test/java
- src/integration-test/resources
- src/main/java
- src/main/resources
- src/test/java
- src/test/resources`
Whenever I run the application or unit tests from within STS, I see that STS is using the resources found under src/integration-test/resources.
I see a duplicate resource warning in STS for files which exist in all 3 resource source folders. For example, I have an application.properties in all 3 source folders and I see following:
The resource is a duplicate of src/integration-test/resources/application.properties and was not copied to the output folder
If I run the application as a JAR or unit tests/integration tests from the command line (via gradle build), everything seems to use the correct resources. This makes me believe it is a problem with how STS/Eclipse is handling gradle.
Does anybody know of how I can configure STS to use the correct resource source folders when using gradle?
I think my problem may be related to (or the same as?) Spring Boot incorrectly loads test configuration when running from eclipse+gradle, https://issuetracker.springsource.com/browse/STS-3882, https://issues.gradle.org/browse/GRADLE-1777
I also tried the solution found here, but that seems to only fix Maven builds:
Spring Tool Suite finds spring-boot integration test configuration and does not start main application
I think my problem may be related to...
Yes, it is related but in my opinion not the same. That problem is caused by the runtime classpath being incorrect. This problem is an error coming from the eclipse project builder so it is a compile-time issue.
The problems are closely related though. Depending on your point of view, you could say they are the same (incorrect mixing of test and compile-time classpaths).
Here, specifically, the problem is that the eclipse builder tries to copy all the resources it finds in source folders to the project's single output folder. Each source folder has a 'application.properties'. The builder warns that it could not copy some of them because one would overwrite the other.
I think there may be a solution for this problem. But it is a solution that really should come from Gradle + ( BuildShip | STS Gradle Tooling) than from you.
It is possible in Eclipse to configure each source-folder individually to target a specific outputfolder. Maven + M2E are doing this correcty, but Gradle + (BuildsShip | STS Gradle Tooling) combdos do not.
For example this is what maven puts into the eclipse .classpath file when it configures a test resources folder:
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
Notice how it explicitly sets the output folder for that entry (to something different from the project's default output folder).
You may be able to address the problem yourself by modifying the .classpath for a gradle project in a similar way. Either by doing it manually or from your build.gradle.
I'm not sure this is worth it however as you will then likely still get hit by the runtime classpath issue (since these folders will still be added to your runtime classpath, your runtime classpath will end-up with two appication.properties resources, one which will 'shadow' the other. See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=482315)
I would say, the right thing to do is add a comment to the issue I linked, and hope they fix it soon as there is only so much you can do yourself by hacking the build.gradle file to modify the .classpath (this can not solve the runtime classpath issue, but in order to solve the runtime classpath issue, they would have to configure source folders to target individual output folder similar to what m2e does).
I would add this as a comment to #Kris's answer but it's too long.
I have solved the runtime classpath issue by adding the code below to my build.gradle file. The code generates an Eclipse launch configuration for the Spring Boot application class and includes only the runtime classpath (i.e. no test JARs).
My project uses the Gradle 'eclipse' plugin to generate the Eclipse project files (which I then import into Eclipse). Running the eclipseClasspath Gradle target will generate the launch file in the project's root directory.
def mainClassName = "com.example.MyApplication"
task eclipseApplicationLaunch {
group "IDE"
description "Generate an Eclipse launch configuration file for the Spring Boot application class"
}
eclipseApplicationLaunch << {
def writer = new FileWriter("${mainClassName.substring(mainClassName.lastIndexOf(".")+1)}.launch")
def xml = new groovy.xml.MarkupBuilder(writer)
xml.doubleQuotes = true
xml.launchConfiguration(type: "org.eclipse.jdt.launching.localJavaApplication") {
listAttribute(key:"org.eclipse.debug.core.MAPPED_RESOURCE_PATHS") {
listEntry(value:"/${project.name}/src/main/java/${mainClassName.replace(".","/")}.java")
}
listAttribute(key:"org.eclipse.debug.core.MAPPED_RESOURCE_TYPES") {
listEntry(value:"1")
}
listAttribute(key:"org.eclipse.jdt.launching.CLASSPATH") {
listEntry(value:"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n<runtimeClasspathEntry containerPath=\"org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/\" javaProject=\"${project.name}\" path=\"1\" type=\"4\"/>\r\n")
listEntry(value:"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n<runtimeClasspathEntry path=\"3\" projectName=\"${project.name}\" type=\"1\"/>\r\n")
configurations.runtime.resolvedConfiguration.resolvedArtifacts.each { artifact ->
def filePath = artifact.file.canonicalPath.replace("\\","/")
listEntry(value:"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n<runtimeClasspathEntry externalArchive=\"${filePath}\" path=\"3\" type=\"2\"/>\r\n")
}
}
booleanAttribute(key:"org.eclipse.jdt.launching.DEFAULT_CLASSPATH", value:"false")
stringAttribute(key:"org.eclipse.jdt.launching.MAIN_TYPE", value:"${mainClassName}")
stringAttribute(key:"org.eclipse.jdt.launching.PROGRAM_ARGUMENTS", value:"--spring.profiles.active=local --spring.config.location=conf/")
stringAttribute(key:"org.eclipse.jdt.launching.PROJECT_ATTR", value:"${project.name}")
stringAttribute(key:"org.eclipse.jdt.launching.VM_ARGUMENTS", value:"-Djava.net.preferIPv4Stack=true")
}
writer.close()
}
eclipseClasspath.dependsOn eclipseApplicationLaunch
I haven't modified the Eclipse .classpath file as per Kris' suggestion. Instead, I have added #Profile("test") to my test application class and #ActiveProfiles("test") to my test classes.

Resources