How can I provide custom logic in a Maven archetype?

送分小仙女□ 提交于 2019-12-20 10:37:07

问题


I'm interested in creating a Maven archetype, and I think I have most of the basics down. However, one thing I'm stuck on is that sometimes I want to use custom logic to fill in a template. For example, if somebody generates my archetype and specifies the artifactId as hello-world, I'd like to generate a class named HelloWorld that simply prints out "Hello World!" to the console. If another person generates it with artifactId = howdy-there, the genned class would be HowdyThere and it would print out "Howdy There!".

I know that under the covers, Maven's archetype mechanism leverages the Velocity Template Engine, so I read this article on creating custom directives. This seemed to be what I was looking for, so I created a class called HyphenatedToCamelCaseDirective that extends org.apache.velocity.runtime.directive.Directive. In that class, my getName() implementation returns "hyphenatedCamelCase". In my archetype-metadata.xml file, I have the following...

<requiredProperties>
    <requiredProperty key="userdirective">
        <defaultValue>com.jlarge.HyphenatedToCamelCaseDirective</defaultValue>
    </requiredProperty>
</requiredProperties>

My template class looks like this...

package ${package};

public class #hyphenatedToCamelCase('$artifactId') {

    // userdirective = $userdirective
    public static void main(String[] args) {
        System.out.println("#hyphenatedToCamelCase('$artifactId')"));
    }
} 

After I install my archetype and then do an archetype:generate by specifying artifactId = howdy-there and groupId = f1.f2, the resulting class looks like this...

package f1.f2;

public class #hyphenatedToCamelCase('howdy-there') {

    // userdirective = com.jlarge.HyphenatedToCamelCaseDirective    
    public static void main(String[] args) {
        System.out.println("#hyphenatedToCamelCase('howdy-there')"));
    }
}

The result shows that even though userdirective is being set the way I expected it to, It's not evaulating the #hyphenatedToCamelCase directives like I was hoping. In the directive class, I have the render method logging a message to System.out, but that message doesn't show up in the console, so that leads me to believe that the method never got executed during archetype:generate.

Am I missing something simple here, or is this approach just not the way to go?


回答1:


The required properties section of the archetype-metatadata xml is used to pass additional properties to the velocity context, it is not meant for passing velocity engine configuration. So setting a property called userDirective will only make the variable $userDirective availble and not add a custom directive to the velocity engine.

If you see the source code, the velocity engine used by maven-archetype plugin does not depend on any external property source for its configuration. The code that generates the project relies on an autowired (by the plexus container) implementation of VelocityComponent.

This is the code where the velocity engine is initialized:

public void initialize()
    throws InitializationException
{
    engine = new VelocityEngine();

    // avoid "unable to find resource 'VM_global_library.vm' in any resource loader."
    engine.setProperty( "velocimacro.library", "" );

    engine.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, this );

    if ( properties != null )
    {
        for ( Enumeration e = properties.propertyNames(); e.hasMoreElements(); )
        {
            String key = e.nextElement().toString();

            String value = properties.getProperty( key );

            engine.setProperty( key, value );

            getLogger().debug( "Setting property: " + key + " => '" + value + "'." );
        }
    }

    try
    {
        engine.init();
    }
    catch ( Exception e )
    {
        throw new InitializationException( "Cannot start the velocity engine: ", e );
    }
}

There is a hacky way of adding your custom directive. The properties you see above are read from the components.xml file in the plexus-velocity-1.1.8.jar. So open this file and add your configuration property

<component-set>
  <components>
    <component>
      <role>org.codehaus.plexus.velocity.VelocityComponent</role>
      <role-hint>default</role-hint>
      <implementation>org.codehaus.plexus.velocity.DefaultVelocityComponent</implementation>
      <configuration>
        <properties>
          <property>
            <name>resource.loader</name>
            <value>classpath,site</value>
          </property>
          ...
          <property>
            <name>userdirective</name>
            <value>com.jlarge.HyphenatedToCamelCaseDirective</value>
          </property>
        </properties>
      </configuration>
    </component>
  </components>
</component-set>

Next add your custom directive class file to this jar and run archetype:generate.

As you see this is very fraglie and you will need to figure a way to distribute this hacked plexus-velocity jar. Depending on what you are planning to use this archetype for it might be worth the effort.



来源:https://stackoverflow.com/questions/16701772/how-can-i-provide-custom-logic-in-a-maven-archetype

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!