I am working on writing a custom plugin that does some post processing of a Jar. The plugin basically runs Websphere’s ejbdeploy utility to generate some EJB-specific class files. It requires that the source and output JARs to be different.
I originally tried to do this by putting my exec task as the finalizer task (finalizedBy) of the jar task. While this works, its not ideal because I must first rename the original jar and then create a new one. This messes up the jar task’s up-to-date functionality and these tasks run every time i build my multi-project. I also tried to setup the task dependencies but because I have an Ear that is being generated in another sub-project, I would have to somehow make the ear task dependent on my ejbdeploy task (something I cant figure out how to do cleanly).
Another alternative solution is to simple execute the rename and exec tasks as actions in a doLast closure on of the jar task. But I’ve read in numerous places that this is not ideal.
Conceptually, the actions I am doing (renaming and then executing a command line program) do not necessarily need to be tasks themselves. Such actions are really a part of the jar task for sub-projects that need this kind of post processing done. So I think I really want these things to be simple actions that are done as part of the jar task. These are tasks only because it was easier to write them that way.
Is my logic sound? Should these really not be tasks and just actions as part of the doLast closure of the jar task?
I faced a similar issue recently, where I had to post-process .class files before using them in run-time. There are some differences, but you might find something interesting in the discussion. I also recommend reading @st_oehme’s reply.
IMHO, having the actions as tasks (or at least as a single separate task) helps with the organization of the plugin. I’d rather have separate tasks added to the build than changing the default tasks. Also, I would avoid renaming the Jar and copying a new over it and/or changing it in place (which as enlightened by @st_oehme in comments for my initial commits, makes you lose the tasks’ up-to-date checks). I would actually create a new Jar (myJarNameEjb.jar or something like that) and use it as input for the Ear task.
I would go with an action, like I explained in the post that @jvff linked. In general an action is the way to go when you somehow need to refine the output of an existing task.
Creating a new jar task would mean you have to reconfigure many aspects of the build to use this jar instead of the standard jar. It might be conceptually cleaner, but a lot more effort than using an action.
I read the linked forum discussion, but the only thing I took away from it was that you advised adding something to doLast. Is that correct?
I found another forum post regarding custom tasks and it suggested an option I could use myself. Namely, it suggested to delegate to project.exec(). My thoughts are I would find the Jar tasks on the project once the graph was ready, and if a property was set on my project, run a method that delegates to project.exec in the doLast part of each of the Jar tasks. My problem is I am unsure how to provide an Action to this exec method. Any suggestions?
Part of the trouble I faced was understanding how the plugin works when written in Java. I finally realized I needed to pass in Action<Task> objects to the jar.doLast() and jar.doFirst() methods. The trick, however, is that it must be done after evaluation, so that it can be done conditionally, based on a extension property my plugin provides.
This exercise has really brought to light the amount of extra code that is necessary to produce a plugin in Java. For the sake learning, I might rewrite this in Groovy and compare them.