Custom Maven Packaging Type
Friday, April 24, 2015 |As I’ve noted in a previous post, I recently moved my blog from Awestruct to
JBake. This also allowed me to migrate the building and publishing of the blog contents to the
toolchain that I know pretty well (Maven). What bothered me, though, was that my POM defined the project as a
jar
packaging type: the build produces no jar file and, in fact, doesn’t process any Java at all. What I wanted,
then, was to be able to define the lifecycle in such a way the the compile
phase didn’t try to compile anything,
and the install
phase didn’t try to put anything in my local repo. Unfortunately, either I’m a bit dense, or the
documentation wasn’t very clear (it’s likely a combination of both :). At any rate, I finally had a eureka moment
late last night and figured it out. Here is a distillation of my findings.
To define a custom packaging type, you define a custom lifecycle and put the packaging type in the role-hint
element.
All of this is done in components.xml
, which is found in src/main/resources/META-INF/plexus
. This file can be
in a project whose packaging
is either pom
or maven-plugin
(others may be possible. I haven’t tried).
At any rate, here is the components.xml
which accomplishes my goal (no pun intended ;) for the JBake Maven plugin:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<component-set>
<components>
<component>
<role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
<role-hint>jbake</role-hint> (1)
<implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
<configuration>
<lifecycles>
<lifecycle>
<id>default</id> (2)
<phases>
<generate-resources></generate-resources>
<process-resources></process-resources>
<compile>
${project.groupId}:${project.artifactId}:${project.version}:generate (3)
</compile>
<process-test-resources></process-test-resources>
<test-compile></test-compile>
<test></test>
<package></package>
<install></install>
<deploy></deploy>
</phases>
</lifecycle>
<lifecycle>
<id>site</id> (2)
<phases>
<pre-site></pre-site>
<site>
${project.groupId}:${project.artifactId}:${project.version}:generate
</site>
<post-site></post-site>
<site-deploy></site-deploy>
</phases>
</lifecycle>
</lifecycles>
</configuration>
</component>
</components>
</component-set>
1 | role-hint defines the new packaging type |
2 | We’re overriding the default and site lifecycles, providing goals only for the relevant phases. |
3 | Note how the desired goal is specified. |
On the plugin side, that’s literally all there is to it. When the target project is configured correctly,
all the user must do to generate the site is issue a simple mvn
, mvn compile
, or mvn site
, and the
site is generated in target/${project.artifactId}
(by default).
The plugin build does, though, need one tweak:
1
2
3
4
5
6
7
8
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
This allows us to update the project metadata without having to edit components.xml
. Bump the version?
Change the artifactId
? No problem, thanks to resource filtering.
In the target project(s), you obviously need to configure the plugin. For my blog build, that looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.steeplesoft</groupId>
<artifactId>steeplesoft-blog</artifactId>
<name>Steeplesoft Blog</name>
<version>1.0-SNAPSHOT</version>
<packaging>jbake</packaging> (1)
<!-- ... -->
<plugin>
<groupId>br.com.ingenieux</groupId>
<artifactId>jbake-maven-plugin</artifactId>
<version>0.0.10-SNAPSHOT</version>
<extensions>true</extensions> (2)
<!-- ... -->
Note that we’ve changed the packaging type now to jbake
(1)
, and we’ve add the plugin to the build
with extensions
set to true (2)
. This is very important, as I understand it, as it instructs Maven to load the plugin
early enough in the process so that our new lifecycles are applied to the project.
And that’s all there is to it. For the curious, you can see this change in action in my fork of
jbake-maven-plugin
on GitHub. I’ve submitted a
PR, but the main project doesn’t seem to be too active, so we’ll what happens and go from there.
At any rate, I hope this adds some clarity to the topic of custom Maven packaging types. If you have questions, comments, criticisms, etc., hit the form below.