I am pretty new to Gradle and I am converting the build of our medium sized application from Maven to Gradle.
Although I searched the documentation, this forum and googled around for a while, I could not find a way to run a JavaExec without forking a new process. Both Ant and Maven support this out of the box, so I am pretty surprised… and also surprised not to see any requests for this in the forum or the bug database…
Did I miss something?
My reasons for not wanting to spawn a new Java process are:
Speed (obviously): we generate about 10 WSDL files using org.apache.cxf.tools.java2ws.JavaToWS and every time it takes about 1-2 sec when it was almost instantaneous using Maven exec-maven-plugin
This would solve the long classpath issue on Windows (“java.io.IOException: CreateProcess error=206, The filename or extension is too long”)
The only workaround I found was to use ant.java but it does not really fit into the nice picture and the stdout is not visible on the flow (only at the end).
HI Lance, thanks for your reply and your proposed implementation!
Just like the workaround I found, I suppose that your implementation would only print the output at the end… (and BTW, since main() is a static method, we should not be calling newInstance on the class but rather make a static method invocation, correct? but that’s another story).
Actually my question, once a workaround has been found, would rather be: is there a reason (other than “we just did not code it”) why the JavaExec task does not allow for non-forked executions? If not, should I raise an enhancement request?
I suppose that your implementation would only print the output at the end
Correct, but you could provide a “smarter” PrintStream which passes through to the logger instead of building up a ByteArrayOutputStream
since main() is a static method, we should not be calling newInstance on the class but rather make a static method invocation
My bad, you are correct
is there a reason (other than “we just did not code it”) why the JavaExec task does not allow for non-forked executions?
My guess is that the normal way to execute a java method in the current JVM is by a simple groovy call. You have a bit of a chicken or egg problem here in that the buildscript classpath is determined before the class is compiled. You could split the JustDoIt class into a separate project to the task. Then the task could reference the JustDoIt project using
I have been playing with your proposed solution for a while and it is not that simple: for instance I do not want the initial class path of Gradle to be visible… (because of a conflict on org.apache.log4j.ConsoleAppender that JustDoIt is using in a different version than Gradle does).
Therefore, I end up calling something like
gradle.class.classLoader.parent.parent
… but this also needs to become the “current class loader” etc… Actually, looking at ant source code so see how what I called successfully in the workaround above is working, I realized that this is made of quite a few steps:
AntClassLoader has this notion of “isolated” mode… all of which I do not want to code inside my task. I could write a plugin, but remember I am pretty new to Gradle… and this seems to me like a very basic task… I wish it could be part of JavaExec since I believe that most people who need this in the future are going to search for the feature… exactly there.
PS: I did not understand the chicken and egg issue: the class path is fixed once and for all and does not depend on the JustDoIt class… (but unless I missed something critical here, let’s not dig into that in order to let the topic focused on the real question, OK?)
These groovy commands use the buildscript classpath (the chicken) 2. The buildscript classpath is determined first 3. I assume JustDoIt.java is in the current project 4. JustDoIt.class does not exist until it is compiled (the egg)
I do not want the initial class path of Gradle to be visible
OK, I understand the chicken and egg issue, thanks. I guess I do not have the issue because my task depends on ‘classes’:
task justDoIt(dependsOn:[classes]) {
...
Playing around with the class loader is definitely the way to go, but it is not as simple as a simple one liner… I ended up having “no class def found” errors for java.io.IOException although rt.jar was in the class path for my class loader… After half a day of attempts and debugging, I just gave up because my ant workaround was equivalent and already functional.
Having something reliable probably needs to be thought about carefully and would deserve being in the standard JavaExec plugin IMHO
I came up with following custom task based on my original workaround. It shares the same issue (no easy logging of the progress) but at least is solves the two issues I had (speed + Windows classpath):