我有兴趣创建一个Maven原型,我想我已经掌握了大部分基础知识。但是,我坚持的一件事是,有时我想使用自定义逻辑来填充模板。例如,如果有人生成我的原型并将artifactId指定为hello-world,我想生成一个名为HelloWorld的类,它只打印出“Hello World!”。到控制台。如果另一个人使用artifactId = howdy-there生成它,那么genned类将是HowdyThere,它将打印出“Howdy There!”。
我知道,Maven的原型机制在幕后使用了Velocity模板引擎,所以我在creating custom directives上阅读了这篇文章。这似乎是我想要的,所以我创建了一个名为HyphenatedToCamelCaseDirective的类,它扩展了org.apache.velocity.runtime.directive.Directive。在该类中,我的getName()实现返回“hyphenatedCamelCase”。在我的archetype-metadata.xml文件中,我有以下内容......
<requiredProperties>
<requiredProperty key="userdirective">
<defaultValue>com.jlarge.HyphenatedToCamelCaseDirective</defaultValue>
</requiredProperty>
</requiredProperties>
我的模板类看起来像这样......
package ${package};
public class #hyphenatedToCamelCase('$artifactId') {
// userdirective = $userdirective
public static void main(String[] args) {
System.out.println("#hyphenatedToCamelCase('$artifactId')"));
}
}
安装我的原型然后做一个原型:通过指定artifactId = howdy-there和groupId = f1.f2生成,结果类看起来像这样......
package f1.f2;
public class #hyphenatedToCamelCase('howdy-there') {
// userdirective = com.jlarge.HyphenatedToCamelCaseDirective
public static void main(String[] args) {
System.out.println("#hyphenatedToCamelCase('howdy-there')"));
}
}
结果表明,尽管userdirective按我预期的方式设置,但它并没有像我希望的那样评估#hyphenatedToCamelCase指令。在指令类中,我让render方法将消息记录到System.out,但是该消息没有出现在控制台中,因此这让我相信在archetype:generate期间永远不会执行该方法。
我在这里错过了一些简单的东西,或者这种方法不是要走的路?
答案 0 :(得分:2)
archetype-metatadata xml的必需属性部分用于将其他属性传递给速度上下文,不用于传递速度引擎配置。因此,设置一个名为userDirective的属性只会使变量$ userDirective可用,而不是向速度引擎添加自定义指令。
如果您看到源代码,maven-archetype插件使用的速度引擎不依赖于其配置的任何外部属性源。 generates the project依赖于VelocityComponent的自动装配(通过plexus容器)实现的代码。
这是初始化速度引擎的代码:
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 );
}
}
有一种添加自定义指令的hacky方法。您在上面看到的属性是从plexus-velocity-1.1.8.jar中的components.xml文件中读取的。因此,打开此文件并添加配置属性
<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>
接下来将自定义指令类文件添加到此jar并运行archetype:generate。
如你所见,这是非常脆弱的,你需要找到一种方法来分发这个被黑的丛速度罐。根据您计划使用此原型的原因,可能值得付出努力。