Parallelizable JAXB/XJC Plugin/Task

tldr; How can I use parallel project execution with a JAXB/XJC plugin?

My team is migrating our build from Maven to Gradle. We have been able to find a suitable plugin for everything we were doing in the previous build. One of the features that swayed us to finally move was the parallel project execution incubating feature. This worked great!!! …until we added in our JAXB/XJC portions of the build.

The gradle-jaxb-plugin[1] worked ok, but it didn’t provide support for current default/best practice builds as it made some assumptions about the project layout rather than using the projects configuration. We forked it, updated it, submitted PR’s, and ultimately ended up publishing our own build[2]. This is publicly accessible and here is an example showing some of the newly added features.

The one thing we can’t get to work is the parallel project execution. The XJC itself is not thread-safe. We haven’t exactly figured out why this is, but it obviously is using some shared space in a non-locking manner as the final code it generates is just mangled and inconsistent.

I found this thread, which referenced this thread, and ultimately this non-merged/closed PR. I will assume this sequence is rather out of date at this point since it is over 2 years old (Aug 2013 through Feb 2014). I also found this thread, but it acknowledges that there are potentially still some concurrency issues.

Since we are already updating the plugin, what do we need to add/do in order to use parallel project execution with the JAXB XJC?
How do we synchronize the execution of that task across the entire multi-project build?

The non-thread-safe nature of the XJC is causing our concurrency issue, I’m just trying to find the work around so we can gain the benefits of parallel builds.

NOTE: These were originally inline links in the text, but as a new user I could only put in 5 links. So here they are in non-link format.
1 - github.com/jacobono/gradle-jaxb-plugin
2 - github.com/rackerlabs/gradle-jaxb-plugin

There is currently no built-in mechanism for declaring that a task is not safe. You could synchronize on a shared (static) lock object.

1 Like

Thanks for the confirmation that this isn’t in the baseline yet. Our first implementation of this is doing just that. We are also looking at possibly using a temp FileLock in order to allow multiple parallel project builds to execute on the same host.

Thoughts?

I guess I’m missing something, but can’t you fork xjc? That would make it
safe to use in parallel.

Unfortunately it appears that you can’t fork the XJC. When you do, the simultaneous builds corrupt each other and the results are in turn unusable. We found this as we tried to use Gradle’s parallel project execution incubating feature. Then as we started investigating it further, we found that even executing XJC in separate JVM’s on the same host caused the same crosstalk interference.

Initially we only need the to execute a single build process on a each host, so simply synchronizing the XJC call on the class as you suggested works well. We were just going to use a built in Gradle feature if it already existed.

We do have a few tests that can’t be executed in parallel either, so we would love to see this feature make it into the Gradle baseline at some point. For the short term, I think we will probably make a Test Lock of some kind in a dependency that all of the tests have in common. We have a similar need as was referenced in the threads mentioned in my original question.

Thanks again for taking the time to answer these newbie questions.

I believe com.sun.tools.xjc.XJC2Task is multi-process safe. Give that one a shot.

That is perfect!!! You are correct that XJC2Task is multi-process safe if used directly. I wonder why the hand off that is supposed to occur from XJCTask is not? Interesting, but I will leave that for another day. Thanks!