How do I get IntelliJ to recognize gradle generated sources dir? - gradle

So I have an XJC javaExec that spins like a top but IntelliJ doesn't recognize the generated output despite having marked generated-src/java as such. Do I need to tweak the idea plug-in or something?
Note: The plug-in itself is loaded in subProjects from the root build.gradle.
XJC Project:
description = "Generates sources and compiles them into a Jar for $project"
configurations { xjc }
dependencies {
xjc 'org.glassfish.jaxb:jaxb-xjc:2.2.11'
xjc 'org.glassfish.jaxb:jaxb-runtime:2.2.11'
}
task xjc (type:JavaExec) {
doFirst{
File generatedSrcDir = file("$buildDir/generated-src/java")
if (!generatedSrcDir.exists()) {
generatedSrcDir.mkdirs()
}
}
main = "com.sun.tools.xjc.XJCFacade"
classpath configurations.xjc
def argsList = [
"-mark-generated",
"-no-header",
"-verbose", // or -quiet or nothing for default.
"-target", "2.1",
"-encoding", "UTF-8",
"-d", "$buildDir/generated-src/java",
"-catalog","$projectDir/src/main/resources/commons-gradle.cat",
file("$projectDir/src/main/resources/v1/") ]
args argsList
inputs.files files(file("$projectDir/src/main/resources/v1/"))
outputs.files files(file("$buildDir/generated-src/java"),file("$buildDir/classes"))
}
compileJava {
dependsOn xjc
source "${buildDir}/generated-src"
}
In the project that depends on this one I simply have:
compile project(":path:to:schemas:the-test-schema")
I've tried:
idea {
module {
def buildDir = file("$buildDir")
def generatedDir = file("$buildDir/generated-src")
def listOfDirs = []
buildDir.eachDir { file ->
if (file.name != buildDir.name && file.name != generatedDir.name)
listOfDirs.add(file)
}
excludeDirs = listOfDirs.toArray()
generatedSourceDirs += file("$buildDir/generated-src/java")
scopes.COMPILE.plus += [ configurations.xjc ]
}
}

I'll point out a solution by Daniel Dekany, from a Gradle discussion thread actually linking to this question. To quote:
apply plugin: "idea"
...
sourceSets.main.java.srcDir new File(buildDir, 'generated/javacc')
idea {
module {
// Marks the already(!) added srcDir as "generated"
generatedSourceDirs += file('build/generated/javacc')
}
}
Works well for me.

The code of this answer, rewritten using Kotlin DSL, will look like this:
plugins {
idea
}
val generatedSourcesPath = file("out/production/classes/generated")
java.sourceSets["main"].java.srcDir(generatedSourcesPath)
idea {
module {
generatedSourceDirs.add(generatedSourcesPath)
}
}

In my case, it didn't work unless I added the generate sources directory to both sourceDirs and generatedSourceDirs:
def generatedSourcesDir = file('src/generated/main/java')
idea {
module {
sourceDirs += generatedSourcesDir
generatedSourceDirs += generatedSourcesDir
}
}

in 2020 you probably did not refresh the project in IDEA
because it actually works oob.
30 mins of reading outdated solutions :(

It's happening in some versions. There are some issues that we can look at and read carefully.
But for myself, from the IntelliJ IDEA 2019 the solutions below aren't working anymore:
https://youtrack.jetbrains.com/issue/IDEA-210065 (it says Obsolete)
https://youtrack.jetbrains.com/issue/IDEA-152581 (it's saying Fixed here)
https://youtrack.jetbrains.com/issue/IDEA-117540/generated-sources-inside-output-directory-are-excluded-by-default
https://intellij-support.jetbrains.com/hc/en-us/community/posts/4906059373074-Class-defined-in-generated-sources-not-found-by-Intellij-editor-but-found-by-compiler-gradle-build-
Discussion in the Gradle forum about this: https://discuss.gradle.org/t/how-do-i-get-intellij-to-recognize-gradle-generated-sources-dir/16847
According to #Daniel Dekany, this worked in IDEA 2017.1.2, and worked for me until 2019:
plugins {
id 'idea'
}
idea {
module {
generatedSourceDirs += file('build/generated/sources/annotationProcessor')
}
}
But from 2019 to 2022, the solution that worked for me was:
def generatedDir = "${buildDir}/generated/sources"
sourceSets {
main {
java {
srcDir generatedDir
}
}
}
idea {
module {
generatedSourceDirs.addAll(file(generatedDir))
}
}

ext {
// path to IDEA generated sources directory
ideaGeneratedSourcesDir = "$projectDir/src/main/generated"
}
compileJava {
//……
options.annotationProcessorGeneratedSourcesDirectory = file(ideaGeneratedSourcesDir)
//options.headerOutputDirectory.set(file(ideaGeneratedSourcesDir)) (tested no effect)
//……
}
// above work for me, and i try all method this question mentioned it's not work! env: idea2019.3, wrapped gradle6.3-all, zh-CN, JDK8, [x] annotation processing is disabled(no effect, in global settings ), no idea plugin([x]plugins {id idea}), [x]sourceSets no need to set(genereated srcDir)
myCodeGenExample:
task vertxCodeGen(type: JavaCompile) {
group 'build'
source = sourceSets.main.java
destinationDir = file(ideaGeneratedSourcesDir)
classpath = configurations.compileClasspath
options.annotationProcessorPath = configurations.annotationProcessor
options.debugOptions.debugLevel = "source,lines,vars"
options.compilerArgs = [
"-proc:only",
"-processor", "io.vertx.codegen.CodeGenProcessor",
// where the non Java classes / non resources are stored (mandatory) - the processors requires this option to know where to place them
"-Acodegen.output=$destinationDir.absolutePath",
]
}
refresh the gradle, continously exist

Related

How to include all src/test/resources/** AND src/main/java/**/*.html in the test sourceset in gradle?

I have the following and thought it was 'adding' to my sourceSet but actually just modified it..
sourceSets {
test {
resources {
srcDirs = ["src/main/java"]
includes = ["**/*.html"]
}
}
}
What I really want is both src/test/resources/** and the above as well. I don't want to exclude any files from src/test/resources though and the above is only including html from any directories I put there.
thanks,
Dean
The following will illustrate the technique using main (so it can be verified):
apply plugin: 'java'
sourceSets {
myExtra {
resources {
srcDirs "src/main/java"
includes = ["**/*.html"]
}
}
main {
resources {
source myExtra.resources
}
}
}
Proof of concept via the command-line:
bash$ ls src/main/java
abc.html
xyz.txt
bash$ ls src/main/resources/
def.html
ijk.txt
bash$ gradle clean jar
bash$ jar tf build/libs/myexample.jar
META-INF/
META-INF/MANIFEST.MF
abc.html
def.html
ijk.txt
In your case, change main to test. This answer was discovered via the Gradle doc for SourceDirectorySet. Interestingly, for 3.0, it contains a TODO:
TODO - configure includes/excludes for individual source dirs
which implies that this work-around (via this method) is probably necessary.
I got your point. I tried this and it worked . Please take a look into it:
sourceSets {
test {
resources {
srcDirs = ["src/main/java"]
includes = ["**/*.html"]
}
}
}
sourceSets.test.resources.srcDir 'src/test/resources'
Add these in build.gradle.
I was thinking whether or not to post this answer. So that if you are not satisfied with the previous answer, try the following hacky way (probably it will work with eclipse command):
apply plugin: 'java'
ConfigurableFileTree.metaClass.getAsSource = {
def fileTrees = delegate.asFileTrees
fileTrees.metaClass.getSrcDirTrees = {
return delegate as Set
}
fileTrees as SourceDirectorySet
}
sourceSets {
main {
resources {
srcDirs = [] // cleanup first
source fileTree('src/main/java').include('**/*.html').asSource
source fileTree('src/main/resources').asSource
}
}
}
Using srcDir may be what you want. Here's an example:
sourceSets {
main {
resources {
srcDir "src/main/resources"
exclude "file-to-be-excluded"
include "file-to-be-included"
srcDir "src/main/java"
include "**/*.html"
srcDir "image-folder-in-root"
include "**/*.png"
include "**/*.jpg"
exclude "**/*.xcf"
}
}
}
Not exactly what you asked for, but it could be helpful for someone who finds this question:
I only wanted to have the test resources next to the sources. So I only need to exclude the sources.
In your case, perhaps you could exclude those which you would mind getting in the JAR and/or classpath.
None of the other answers worked for me, and this did work:
sourceSets {
test {
resources {
srcDirs += "src/test/kotlin"
excludes = ["**/*.kt"]
}
}
}
Gradle 6.3.

How to add gradle generated source folder to Eclipse project?

My gradle project generates some java code inside gen/main/java using annotation processor. When I import this project into Eclipse, Eclipse will not automatically add gen/main/java as source folder to buildpath. I can do it manually. But is there a way to automate this?
Thanks.
You can easily add the generated folder manually to the classpath by
eclipse {
classpath {
file.whenMerged { cp ->
cp.entries.add( new org.gradle.plugins.ide.eclipse.model.SourceFolder('gen/main/java', null) )
}
}
}
whereby null as a second constructor arg means that Eclipse should put the compiled "class" files within the default output folder. If you want to change this, just provide a String instead, e.g. 'bin-gen'.
I think it's a little bit cleaner just to add a second source directory to the main source set.
Add this to your build.gradle:
sourceSets {
main {
java {
srcDirs += ["src/gen/java"]
}
}
}
This results in the following line generated in your .classpath:
<classpathentry kind="src" path="src/gen/java"/>
I've tested this with Gradle 4.1, but I suspect it'd work with older versions as well.
Andreas' answer works if you generate Eclipse project from command line using gradle cleanEclipse eclipse. If you use STS Eclipse Gradle plugin, then you have to implement afterEclipseImport task. Below is my full working snippet:
project.ext {
genSrcDir = projectDir.absolutePath + '/gen/main/java'
}
compileJava {
options.compilerArgs += ['-s', project.genSrcDir]
}
compileJava.doFirst {
task createGenDir << {
ant.mkdir(dir: project.genSrcDir)
}
createGenDir.execute()
println 'createGenDir DONE'
}
eclipse.classpath.file.whenMerged {
classpath - >
def genSrc = new org.gradle.plugins.ide.eclipse.model.SourceFolder('gen/main/java', null)
classpath.entries.add(genSrc)
}
task afterEclipseImport(description: "Post processing after project generation", group: "IDE") {
doLast {
compileJava.execute()
def classpath = new XmlParser().parse(file(".classpath"))
new Node(classpath, "classpathentry", [kind: 'src', path: 'gen/main/java']);
def writer = new FileWriter(file(".classpath"))
def printer = new XmlNodePrinter(new PrintWriter(writer))
printer.setPreserveWhitespace(true)
printer.print(classpath)
}
}

(No such file or directory) how to make non existant file to be ignored by gradle

when i run the command 'gradle tasks' or anything for that fact, i got the following error:
Caused by: java.io.FileNotFoundException: /Users/maxit/workspace/Backbone/modules/contact-form/public/build/contact-src.js (No such file or directory)
Here is my gradle build file:
configurations {
sshAntTask
}
dependencies {
sshAntTask 'org.apache.ant:ant-jsch:1.7.1', 'jsch:jsch:0.1.29'
}
// Pull the plugin from Maven Central
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.eriwen:gradle-js-plugin:1.5.0'
}
}
// Invoke the plugin
apply plugin: 'js'
apply plugin:'base'
def appName = "some"
def version = "0.0.1"
def jsSrcDir = 'public/js'
javascript.source {
dev {
js {
srcDir jsSrcDir
include "*.js"
exclude "*.min.js"
}
}
prod {
js {
srcDir jsSrcDir
include "*.min.js"
}
}
}
task combineSrc(type: com.eriwen.gradle.js.tasks.CombineJsTask) {
source = ["${projectDir}/public/templates/templates.js","${projectDir}/public/js/models/contact_model.js", "${projectDir}/public/js/views/contact_form_view.js", "${projectDir}/public/js/app.js" ]
dest = file("${projectDir}/public/build/${appName}-src.js")
}
task appendJQuery(dependsOn: 'combineSrc') {
String backboneSrc = file(new File("${projectDir}/public/build/${appName}-src.js")).text
new File("${projectDir}/public/build/${appName}-jqueryWraped.js").withWriter{ out ->
out << "(function(\$){" + file("${projectDir}/public/build/${appName}-src.js").text + "})(jQuery); \n"
}
}
It appears, that gradle doesn't ignore a file that is none existant. The task 'combineSrc' hasn't been run, yet to create the file....and i am unable to run the task 'cobineSrc' to create the file in the first place. Its kind a dead end. what am i doing wrong and how to make this work? Thank you
The reason you're failing is, that all the stuff you currently doing during the configuration of the appendJQuery task should be done in the execution phase.
just refactor your appendJQuery task to do:
task appendJQuery(dependsOn: 'combineSrc') {
doLast{
String backboneSrc = file(new File("${projectDir}/public/build/${appName}-src.js")).text
new File("${projectDir}/public/build/${appName}-jqueryWraped.js").withWriter{ out ->
out << "(function(\$){" + file("${projectDir}/public/build/${appName}-src.js").text + "})(jQuery); \n"
}
}
}
hope that helps!
René

How to keep Java code and Junit tests together building with Gradle

I have a project in which the main source and the test cases for that source are kept in the same package/directory. Each test class is the name of the class which it is testing with "Test" appended on the end. So if I have a Foo.java there will be a FooTest.java right next to it.
My question is, how do I build this project with Gradle? I'd still like to keep the class files separate, i.e. a folder for main classes and a folder for test classes.
This should do the trick:
sourceSets {
main {
java {
srcDirs = ["some/path"]
exclude "**/*Test.java"
}
}
test {
java {
srcDirs = ["some/path"]
include "**/*Test.java"
}
}
}
For reference, here is the code I used to try to get around the Eclipse plugin's classpath issue. Using this in combination with Peter's answer above seems to work.
// The following ensures that Eclipse uses only one src directory
eclipse {
classpath {
file {
//closure executed after .classpath content is loaded from existing file
//and after gradle build information is merged
whenMerged { classpath ->
classpath.entries.removeAll { entry -> entry.kind == 'src'}
def srcEntry = new org.gradle.plugins.ide.eclipse.model.SourceFolder('src', null)
srcEntry.dir = file("$projectDir/src")
classpath.entries.add( srcEntry )
}
}
}
}
this work for me:
eclipse {
classpath {
file {
withXml {
process(it.asNode())
}
}
}
}
def process(node) {
if (node.attribute('path') == 'src/test/java' || node.attribute('path') == 'src/test/resources')
node.attributes().put('output', "build/test-classes")
else
node.children().each {
process(it)
}}

how to get version number or something else into my zip archive in gradle

EDIT:
I am trying to run these two commands and get these results in a gradle subproject...
gradle assemble -> databus-Developer-Build.zip
gradle -DmyVersion=1.0.2 -> databus-1.0.2.zip
Currently, my output is databus-null.zip IF I use $version instead of $myVersion. When using $MyVersion, I get the error "myVersion is not a property on that task". :( :(.
EDIT
So, trying out the first answer completely failed with "Could not find property $myVersion on task ':webserver:myZip"
NOTE: I am trying to do this in a subproject right now. Here is the subproject gradle code...
project(':webserver') {
project.ext.genLibDir = file('lib')
project.ext.fixedLibDir = file('../master/libother')
dependencies {
compile project(':master')
compile fileTree(dir: '../webserver/lib', include: '*.jar')
compile fileTree(dir: '../webserver/play-1.2.4/framework/lib', include: '*.jar')
compile fileTree(dir: '../webserver/play-1.2.4/framework', include: 'play-*.jar')
}
task deleteJars(type: Delete) {
ext.collection = files { genLibDir.listFiles() }
delete ext.collection
}
task copyJars(type: Copy) {
from(configurations.compile) {}
from(fixedLibDir) {}
into genLibDir
}
copyJars.dependsOn('deleteJars')
classes.dependsOn('copyJars')
task myZip(type: Zip) {
archiveName "dashboard-"+$myVersion+".zip"
from('..') {
include 'webserver/run*.sh'
include 'webserver/app/**'
include 'webserver/conf/**'
include 'webserver/play-1.2.4/**'
include 'webserver/public/**'
}
}
assemble.dependsOn('myZip')
//playframework has it's own generation of .classpath and .project fils so do not
//overwrite their versions. NEED to call "play.bat eclipsify" here...
task eclipse(overwrite: true) {
}
gradle.taskGraph.whenReady {taskGraph ->
if (taskGraph.hasTask(assemble) && myVersion == null) {
myVersion = 'Developer-Build'
}
}
}
thanks,
Dean
I think the reason that you get the error "myVersion is not a property on that task" is, that you have to pass the property with -P instead of "-D"
ok, the correct answer is doing something like this...(add this to allprojects section)..
if (project.hasProperty('myVersion')) {
project.ext.xVersion = project.myVersion
} else {
project.ext.xVersion = 'Developer-Build'
}
and interestingly enough this below one does NOT work because 'version' seems to be some sort of reserverd property and is set to unspecified on startup...
if (project.hasProperty('version')) {
project.ext.xVersion = project.version
} else {
project.ext.xVersion = 'Developer-Build'
}
Seeing as version seems to be a reserved property, it is most likely used in publishing artifacts so the best solution then maybe the following
if (project.hasProperty('myVersion')) {
project.version = project.myVersion
} else {
project.version = 'Developer-Build'
}
and the automated build passes in myVersion and developers of course don't.

Resources