As some of you may know, I’m currently working on the WCMS project at the Australian Broadcasting Corporation. This is a large, multi-year project to replace the old web content management system with a brand new (Java) CoreMedia system which will allow the ABC to grow it’s online presence even further.
As with most java based systems, we use maven to support building the project. And we use many of the plugins that are out there to do specific tasks, for instance the maven-config-processor-plugin to create the various configurations for each of the target platforms, but also the maven-shade-plugin to change some .class files in specific jars.
To create a maven plugin, you will need the maven-plugin-api, which you configure in the dependencies part of the pom.xml:
Note that instead of packaging this as a jar, it’s packaged as a maven-plugin. Also, because we’ll be using annotations in the actual java source, we’ll set the source and target to use java 5.
Next, we’ll have to write some code that actually knows how to join an array of Files to another File. Thankfully, the AbstractMojo already has a everything on board to create a plugin. Just create a class that extends the AbstractMojo and implement the execute() method. Note that the class is annotated in the javadoc using the @goal and @phase annotations. These define the goal (in this case, it will be filejoiner:join) and the phase for the plugin (I chose prepare-package as I needed to join the files only when we’re constructing the final jar)
As we’re joining a list of files to a single file, we need a targetFile and an array of sourceFiles. We mark these in the javadoc as @parameter and make sure they are required by marking them @required. When using our plugin in another maven project, it will now know the names of the parameters as well as inform you that you’ve forgotten to provide them. The rest of the source is pretty straight forwarded, we open a file for writing/appending and we’ll read the array of source files and append them to the target file, we throw in some getters and setters and we’re done. I could have made the encoding configurable too, but I didn’t because I always use UTF-8 and I strongly think everybody should 😉
And that is all that there is to it. How maven knows to use this class? No magic there, just because you annotated it with @goal, it will be picked up by maven. So you can put multiple goals in one plugin, nicely separated into different classes. Of course, to deploy this plugin to your repository, you will need to add a ‘distributionManagement’ section to your pom.xml, but if you just have a local repository, running ‘mvn install’ will do.
Now, to use our plugin in another project, we’ll need to configure it as a plugin. We already decided that the execution phase for this plugin was to be ‘prepare-package’, so, we configure the ‘join’ task during that phase and we configure some sourceFiles and a targetFile:
So, now, whenever we run the ‘prepare-package’ or during any later phase, our plugin will take 1.txt and 2.txt and append them to a new or existing combined.txt. Easy does it. I’m pretty sure that writing the plugin, distributing and configuring it in our project actually took less time than this blog post 🙂