Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maven archetype - optional property, empty by default

I want to be able to generate a project from my archetype with one of the properties being empty by default, or populated if specified so on the command line.

This is my archetype-metadata.xml:

<?xml version="1.0" encoding="UTF-8"?>
<archetype-descriptor name="basic">
    <requiredProperties>
        <requiredProperty key="compilerVersion"/>
        <requiredProperty key="dependencyClassifier">
            <defaultValue></defaultValue>
        </requiredProperty>
    </requiredProperties>
</archetype-descriptor>

This is not working. If there is any non-whitespace value in dependencyClassifier, then it works flawlessly. However, I cannot get it to work with the default value being "empty".

The error I get when defaultValue is empty/null is:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-archetype-plugin:2.4:generate (default-cli) on project standalone-pom: Archetype com.avast.archetype:compile-java:1.0.21 is not configured
[ERROR] Property dependencyClassifier is missing.
[ERROR] -> [Help 1]

Alternatively, I would accept being able to pass an empty-value (or "whitespace" value) on the command line. Again, using "-DdependencyClassifier= " does not work.

How do I specify a property should be empty by default?

Thanks


What I want to achieve with this is to be able to create a project from an archetype, which contains a dependency declaration:

    <dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>artifact</artifactId>
            <version>${dependencyVersion}</version>
            <classifier>${dependencyClassifier}</classifier>
        </dependency>
    </dependencies>

and I need to be able to instantiate ${dependencyClassifier} on archetype creation. This is possible for ${dependencyVersion}, because that will never be empty. Classifier, however, should be empty by default.

like image 629
Martin Melka Avatar asked Mar 12 '23 11:03

Martin Melka


2 Answers

This is how I successed meeting your requirements:

In the template pom.xml file for the to-be-generated Maven project, place an empty property, but don't use it as placeholder of the classifier value, there you will still use the archetype requiredProperty placeholder as following:

<properties>
    <!-- empty placeholder, document it accordingly -->
    <empty.property></empty.property>
</properties>

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
        <classifier>${dependencyClassifier}</classifier>
    </dependency>
</dependencies>

Then, in your archetype-metadata.xml have the following:

<requiredProperties>
    <requiredProperty key="dependencyClassifier">
        <defaultValue>${empty.property}</defaultValue>
    </requiredProperty>
</requiredProperties>

Note the matchings:

  • The ${empty.property} default value here is just a non existing property for the Archetype Plugin, which is accepted (an empty value would not work indeed).
  • The dependencyClassifier now has a default value, which is ${empty.property}
  • On the generated project though, empty.property would be empty (if dependencyClassifier was not specified during the mvn archetype:generate call), because it exists as Maven property, with empty value, which makes the whole valid for Maven: the property value injected by the archetype is a declared property in the final pom and as such not breaking anything.
  • The classifier will hence have either dependencyClassifier value (specified at runtime) or empty.property (its default value), which is empty
  • An empty classifier is treated by Maven as no classifier, as such providing us both behaviors.

To summarize:

Invoking

mvn archetype:generate ... -DdependencyClassifier=something

Would effectively populate the classifier element with something, our desired classifier at runtime.

Instead, not specifying any value will leave classifier with ${empty.property}, that is, empty. An Maven will no look for any classifier (nor complain).

The only drawback of this approach is to keep an empty.property property for no much meaning in your final pom.xml, it's a trick which may shock some purists, but does the job.

like image 90
A_Di-Matteo Avatar answered Mar 19 '23 08:03

A_Di-Matteo


I had a similar case and, applied to your use case, solved it like this:

In archetype-metadata.xml, define _UNDEFINED_ (or some other magic string) as the default value:

<?xml version="1.0" encoding="UTF-8"?>
<archetype-descriptor name="basic">
  <requiredProperties>
    <requiredProperty key="compilerVersion"/>
    <requiredProperty key="dependencyClassifier">
      <defaultValue>_UNDEFINED_</defaultValue>
    </requiredProperty>
  </requiredProperties>
</archetype-descriptor>

In the <dependency> section of the template pom.xml, use a VTL #if directive:

<dependencies>
  <dependency>
    <groupId>com.example</groupId>
    <artifactId>artifact</artifactId>
    <version>${dependencyVersion}</version>
#if( ${dependencyClassifier} != "_UNDEFINED_" )
    <classifier>${dependencyClassifier}</classifier>
#end
  </dependency>
</dependencies>

So your final pom.xml just does not contain a <classifier> definition at all if you omit -DdependencyClassifier=something with archetype:generate. Which I guess is definitely satisfying purists. Even if the code in the archetype itself may not.

Note: According to the dependency list of archetype-common, the current version 3.1.2 of Maven archetype plugin uses Apache Velocity Engine 1.7.

like image 33
msa Avatar answered Mar 19 '23 10:03

msa