Change package property in Maven Archetype

wvdz picture wvdz · Aug 22, 2016 · Viewed 9.7k times · Source

I created a Maven Archetype. My META-INF/maven/archetype-metadata.xml looks like this:

<archetype-descriptor xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd">

  <fileSets>
    <fileSet filtered="true" packaged="true" encoding="UTF-8" >
      <directory>src/main/java</directory>
    </fileSet>
  </fileSets>

</archetype-descriptor>

This works, as in that it creates a Java source folder and puts my classes in the package as defined by the groupId and the artifactId.

However, I want to modify his package name. For example, if my groupId is com.example and my artifactId wvdz, then my package should be:

com.example.wvdz.mypackage

Question: How do I accomplish this?

Answer

A_Di-Matteo picture A_Di-Matteo · Aug 31, 2016

To accomplish your objectives and since you are already using the packaged attribute to true (explained later), you can simply add directories to your path below.

Keeping the same configuration, with an additional include element as following:

<fileSets>
    <fileSet filtered="true" packaged="true" encoding="UTF-8" >
      <directory>src/main/java</directory>
        <includes>
            <include>**/*.java</include>
        </includes>       
    </fileSet>
</fileSets>

You could then place under src/main/java/mypackage your Java sources templated where the package statement would be as following:

package ${package}.mypackage

Note the .mypackage reflects exactly the mypackage folder directly under src/main/java. However, when creating the archetype, Maven will then place as a folder (and as such as a package) in between the ${package} property value, which by default would be the ${groupId}.

You can always pass the -Dpackage property and override it the default value (the groupId), which will then be used as a prefix of the package, based on the template above.

This happens because of the packaged attribute set to true in the fileSet section above. In this case true means: add to it the folder hierarchy specified by the ${package} property. Setting it at false would result in ${package} ignored, which can be used if you really want to hard-code the folder structure and obviously reflect it in to the package statement of your Java code, for consistency.


The behavior above is documented in the official How is metadata about an archetype stored?:

the archetype defines a single fileset:

  • the fileset will take all the files in archetype-resources/src/main/java that match the **/*.java pattern
  • the selected files will be generated using the Velocity engine (filtered=true)
  • the files will be generated in the src/main/java directory of the generated project in the same directory as in the JAR file, but with that directory prepended by the package property.

And also:

Filesets can be packaged, which means the selected files will be generated/copied in a directory structure that is prepended by the package property. They can be non-packaged, which means that the selected files will be generated/copied without that prepend.

The same details (about the packaged property) can also be found in the official Archetype Descriptor Model.


Another possible solution is to use an additional property or define your package property value directly in the archetype-metadata.xml file as following:

<archetype-descriptor
    xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd">

    <fileSets>
        <fileSet filtered="true" packaged="true" encoding="UTF-8">
            <directory>src/main/java</directory>
        </fileSet>
    </fileSets>

    <requiredProperties>
        <requiredProperty key="package">
            <defaultValue>${groupId}.${artifactId}.mypackage</defaultValue>
        </requiredProperty>
    </requiredProperties>

</archetype-descriptor>

Note the new requiredProperties section: here we are setting the default value for the package property, no need to provide it at runtime anymore (yet possible to override the value above though).

As such, the Java source template under src/main/java (no need for further static folders) would simply be:

package ${package}

During the creation (archetype:generate) Maven will then use the com.sample.something.mypackage as package value (in the Java source file) and populate the packageInPathFormat property with the value com/sample/something/mypackage (the same property, but in path format) and create the desired package hierarchy, consistent with what the Java source code would expect to be placed in.