rackerlabs / gradle-jaxb-plugin

Gradle plugin to ease projects that use xsds and the ant jaxb task
GNU General Public License v2.0
34 stars 21 forks source link

Full incremental task support and/or cleanup #8

Closed bickelj closed 7 years ago

bickelj commented 7 years ago

Given an xsd, this plugin, using https://github.com/sabomichal/immutable-xjc to generate jaxb java files, and setting compileJava to depend on xjc task, when I comment out some of the xsd such that one class will now no longer be generated, the old (outdated, unused) class is still left in the destination directory.

Running gradle clean task as an attempted workaround, it turns out all the java files are still left in the destination directory if we don't put them into gradle's build directory tree.

Workaround for now is to send the output from xjc to an intermediate directory in the build directory, then add a copy task, that will copy from the intermediate directory to the java source directory, set this copy task to depend on xjc, set compileJava to depend on copy task. In this way, gradle clean task now will remove the outdated files from build directory, and running compileJava will get the exact latest classes compiled. Incremental builds still work pretty well, because xjc seems to support it, and then compileJava also notices that the java files are exactly the same. But the issue remains that a class is left in the destination directory.

It seems like there must be another better way. Any suggestions?

wdschei commented 7 years ago

@bickelj ,

This sounds like it may be a bug in this plugin, however it will take some investigation.

Do you happen to have a small project ( Short, Self Contained, Correct (Compilable), Example ) that demonstrates what you are describing? Additionally showing your current work around in comments would be great too.

Kindest regards, Bill

bickelj commented 7 years ago

@wdschei Thanks for the reply, I will get a small example up in a few days. Right now having issues with gradle plugin endpoint tls config or something like that.

bickelj commented 7 years ago

See an example here:

https://github.com/bickelj/gradle-jaxb-plugin/tree/incrementalExample/examples/incremental-build

wdschei commented 7 years ago

@bickelj Thanks for the great example. I was able to duplicate your issue. There are a couple of things that are a little out of the ordinary. Normally, you don't want to have any generated files in your regular source tree. This leads to confusion in the version control system or to requiring special rules for what is ignored. You actually want to have the intermediate directory in the build directory and just add this directory to the source locations of the compileJava task. This also eliminates the copy task you mentioned in your current workaround.

This can be accomplished in your example by replacing this:

jaxb {
    xjc {
        destinationDir = "src/main/java"
    }
}

compileJava.dependsOn(xjc)

with

def generatedDir = "${buildDir}/src/generated-sources"

jaxb {
    xjc {
        destinationDir = generatedDir
    }
}

compileJava {
    source += generatedDir
    dependsOn(xjc)
}

However, this doesn't correct the initial issue you experienced of this plugin not removing the results of a previous execution and in turn leaving files that are no longer desired. This is a bug and will be fixed shortly. This is actually a side effect of a feature in the XJC. It allows the results of multiple executions to be delivered to the same tree. This feature is not utilized in this plugin, but since the plugin did not originally account for this feature it was root cause of the initial issue.

Until this is fixed, the modifications mentioned above will allow a clean to remove all of the generated files. The fix will be deleting the registered output directory for this task (i.e. jaxb -> xjc -> destinationDir) every time the Up To Date check fails. That said, you will definitely not want to use your main source tree as this value like in your original example.

bickelj commented 7 years ago

@wdschei Thank you for working on a fix and for the helpful hints on how to effectively use the plugin.

The situation is a little more complicated than this example. Suppose there are multiple modules, each producing a jar. Module A contains solely code generated by xjc. Module B contains code depending on Module A. When an IDE is opened, the IDE is expecting to see the source code for classes that Module B depends on. Will the example of adding the generatedDir (inside build) to compileJava.source allow the IDE to see it?

I will try it soon, but I am suspecting the IDE won't see it.

Thanks again!

wdschei commented 7 years ago

Whether or not an IDE recognizes the generated code is IDE specific. By adding the generatedDir to the compileJava's sources, IntelliJ IDEA will pick them up. The scenario I presented is exactly how our main project uses this plugin.

bickelj commented 7 years ago

Thanks for the example. Hmm, for some reason in IntelliJ IDEA didn't pick up the sources on the first attempt. I was probably missing some of the additional configuration.

For now we ignore java source in version control for the auto-generated module.

Either way, thanks for working on the issue, it helps, and thanks for maintaining this plugin, much appreciated!

wdschei commented 7 years ago

@bickelj Glad we could help. Like I said, we use this plugin in our main project, so I expect we will be maintaining it for the foreseeable future.

Glad to hear this project is not just useful to us.

wdschei commented 7 years ago

@bickelj v2.4.0 was just released with this fix and is live on the Gradle Plugins Portal.

wdschei commented 7 years ago

@bickelj We had some issues publishing v2.4.0 to the Gradle Plugins Portal, but the fix you are looking for is in v2.4.1 which is now fully published and ready for consumption.

bickelj commented 7 years ago

@wdschei v2.4.1 works beautifully, thank you again!

wdschei commented 7 years ago

@bickelj Glad to here it.