-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a velocity template based generator (#269)
Co-authored-by: Konrad Windszus <[email protected]> Co-authored-by: Hervé Boutemy <[email protected]>
- Loading branch information
1 parent
a600f25
commit 394178a
Showing
14 changed files
with
628 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
modello-maven-plugin/src/main/java/org/codehaus/modello/maven/ModelloVelocityMojo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package org.codehaus.modello.maven; | ||
|
||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
|
||
import java.io.File; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.Properties; | ||
import java.util.stream.Collectors; | ||
|
||
import org.apache.maven.plugins.annotations.LifecyclePhase; | ||
import org.apache.maven.plugins.annotations.Mojo; | ||
import org.apache.maven.plugins.annotations.Parameter; | ||
import org.codehaus.modello.plugin.velocity.VelocityGenerator; | ||
|
||
/** | ||
* Creates files from the model using Velocity templates. | ||
* <p> | ||
* This mojo can be given a list of templates and a list of parameters. | ||
* Each template from the {@link #templates} property will be run with the following context: | ||
* <ul> | ||
* <li>{@code version}: the version of the model to generate</li> | ||
* <li>{@code model}: the modello model</li> | ||
* <li>{@code Helper}: a {@link org.codehaus.modello.plugin.velocity.Helper} object instance</li> | ||
* <li>any additional parameters specified using the {@link #params} property</li> | ||
* </ul> | ||
* The output file is controlled from within the template using the {@code #MODELLO-VELOCITY#SAVE-OUTPUT-TO} | ||
* <a href="https://velocity.apache.org/engine/2.3/vtl-reference.html#directives">VTL directive</a>. | ||
* This allows a single template to generate multiple files. For example, the following | ||
* directive will redirect further output from the template to a file named | ||
* {@code org/apache/maven/api/model/Plugin.java} if the variable {@code package} is set to | ||
* {@code org.apache.maven.api.model} and the variable {@code className} is set to {@code Plugin}. | ||
* <p> | ||
* {@code #MODELLO-VELOCITY#SAVE-OUTPUT-TO ${package.replace('.','/')}/${className}.java} | ||
*/ | ||
@Mojo( name = "velocity", defaultPhase = LifecyclePhase.GENERATE_SOURCES, threadSafe = true ) | ||
public class ModelloVelocityMojo | ||
extends AbstractModelloGeneratorMojo | ||
{ | ||
/** | ||
* The output directory of the generated files. | ||
*/ | ||
@Parameter( defaultValue = "${project.build.directory}/generated-sources/modello", required = true ) | ||
private File outputDirectory; | ||
|
||
/** | ||
* A list of template files to be run against the loaded modello model. | ||
* Those are {@code .vm} files as described in the | ||
* <a href="https://velocity.apache.org/engine/devel/user-guide.html">Velocity Users Guide</a>. | ||
*/ | ||
@Parameter | ||
private List<File> templates; | ||
|
||
/** | ||
* A list of parameters using the syntax {@code key=value}. | ||
* Those parameters will be made accessible to the templates. | ||
*/ | ||
@Parameter | ||
private List<String> params; | ||
|
||
protected String getGeneratorType() | ||
{ | ||
return "velocity"; | ||
} | ||
|
||
protected void customizeParameters( Properties parameters ) | ||
{ | ||
super.customizeParameters( parameters ); | ||
Map<String, String> params = this.params != null ? this.params.stream().collect( Collectors.toMap( | ||
s -> s.substring( 0, s.indexOf( '=' ) ), s -> s.substring( s.indexOf( '=' ) + 1 ) | ||
) ) : Collections.emptyMap(); | ||
parameters.put( "basedir", Objects.requireNonNull( getBasedir(), "basedir is null" ) ); | ||
Path basedir = Paths.get( getBasedir() ); | ||
parameters.put( VelocityGenerator.VELOCITY_TEMPLATES, templates.stream() | ||
.map( File::toPath ) | ||
.map( basedir::relativize ) | ||
.map( Path::toString ) | ||
.collect( Collectors.joining( "," ) ) ); | ||
parameters.put( VelocityGenerator.VELOCITY_PARAMETERS, params ); | ||
} | ||
|
||
protected boolean producesCompilableResult() | ||
{ | ||
return true; | ||
} | ||
|
||
public File getOutputDirectory() | ||
{ | ||
return outputDirectory; | ||
} | ||
|
||
public void setOutputDirectory( File outputDirectory ) | ||
{ | ||
this.outputDirectory = outputDirectory; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<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"> | ||
<parent> | ||
<artifactId>modello-plugins</artifactId> | ||
<groupId>org.codehaus.modello</groupId> | ||
<version>2.1.0-SNAPSHOT</version> | ||
</parent> | ||
|
||
<modelVersion>4.0.0</modelVersion> | ||
<artifactId>modello-plugin-velocity</artifactId> | ||
<name>Modello Velocity Plugin</name> | ||
<description> | ||
Modello Velocity Plugin generates files from the Modello model using Velocity templates. | ||
</description> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.codehaus.modello</groupId> | ||
<artifactId>modello-plugin-xml</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.codehaus.plexus</groupId> | ||
<artifactId>plexus-utils</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.apache.velocity</groupId> | ||
<artifactId>velocity-engine-core</artifactId> | ||
<version>2.3</version> | ||
</dependency> | ||
</dependencies> | ||
</project> |
193 changes: 193 additions & 0 deletions
193
...ns/modello-plugin-velocity/src/main/java/org/codehaus/modello/plugin/velocity/Helper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
package org.codehaus.modello.plugin.velocity; | ||
|
||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
|
||
import java.util.ArrayList; | ||
import java.util.Iterator; | ||
import java.util.List; | ||
|
||
import org.codehaus.modello.ModelloRuntimeException; | ||
import org.codehaus.modello.model.ModelAssociation; | ||
import org.codehaus.modello.model.ModelClass; | ||
import org.codehaus.modello.model.ModelField; | ||
import org.codehaus.modello.model.Version; | ||
import org.codehaus.modello.plugin.AbstractModelloGenerator; | ||
import org.codehaus.modello.plugins.xml.metadata.XmlAssociationMetadata; | ||
import org.codehaus.modello.plugins.xml.metadata.XmlClassMetadata; | ||
import org.codehaus.modello.plugins.xml.metadata.XmlFieldMetadata; | ||
import org.codehaus.plexus.util.StringUtils; | ||
|
||
/** | ||
* Helper class to use inside velocity templates. | ||
* <p> | ||
* This will be made available using {@code ${Helper}} inside the template. | ||
* For example, the following line will return the list of ancestors for a given modello class: | ||
* </p> | ||
* <p> | ||
* {@code #set ( $ancestors = $Helper.ancestors( $class ) )} | ||
* </p> | ||
*/ | ||
@SuppressWarnings( "unused" ) | ||
public class Helper | ||
{ | ||
private final Version version; | ||
|
||
public Helper( Version version ) | ||
{ | ||
this.version = version; | ||
} | ||
|
||
/** | ||
* Returns the capitalised version of the given string. | ||
*/ | ||
public String capitalise( String str ) | ||
{ | ||
return StringUtils.isEmpty( str ) ? str : Character.toTitleCase( str.charAt( 0 ) ) + str.substring( 1 ); | ||
} | ||
|
||
/** | ||
* Returns the uncapitalised version of the given string. | ||
*/ | ||
public String uncapitalise( String str ) | ||
{ | ||
return StringUtils.isEmpty( str ) ? str : Character.toLowerCase( str.charAt( 0 ) ) + str.substring( 1 ); | ||
} | ||
|
||
/** | ||
* Returns the singular name for the given string. | ||
*/ | ||
public String singular( String str ) | ||
{ | ||
return AbstractModelloGenerator.singular( str ); | ||
} | ||
|
||
/** | ||
* Returns the list of ancestors for the given {@code ModelClass}. | ||
*/ | ||
public List<ModelClass> ancestors( ModelClass clazz ) | ||
{ | ||
List<ModelClass> ancestors = new ArrayList<>(); | ||
for ( ModelClass cl = clazz; cl != null; cl = cl.getSuperClass() != null | ||
? cl.getModel().getClass( cl.getSuperClass(), version ) : null ) | ||
{ | ||
ancestors.add( 0, cl ); | ||
} | ||
return ancestors; | ||
} | ||
|
||
/** | ||
* Returns the {@code XmlClassMetadata} for the given {@code ModelClass}. | ||
*/ | ||
public XmlClassMetadata xmlClassMetadata( ModelClass clazz ) | ||
{ | ||
return (XmlClassMetadata) clazz.getMetadata( XmlClassMetadata.ID ); | ||
} | ||
|
||
/** | ||
* Returns the {@code XmlFieldMetadata} for the given {@code ModelField}. | ||
*/ | ||
public XmlFieldMetadata xmlFieldMetadata( ModelField field ) | ||
{ | ||
return (XmlFieldMetadata) field.getMetadata( XmlFieldMetadata.ID ); | ||
} | ||
|
||
/** | ||
* Returns the {@code XmlAssociationMetadata} for the given {@code ModelField}. | ||
*/ | ||
public XmlAssociationMetadata xmAssociationMetadata( ModelField field ) | ||
{ | ||
return (XmlAssociationMetadata) ( (ModelAssociation) field ) | ||
.getAssociationMetadata( XmlAssociationMetadata.ID ); | ||
} | ||
|
||
/** | ||
* Checks if the given {@code ModelField} is a flat item. | ||
*/ | ||
public boolean isFlatItems( ModelField field ) | ||
{ | ||
return field instanceof ModelAssociation && xmAssociationMetadata( field ).isFlatItems(); | ||
} | ||
|
||
/** | ||
* Returns a list of all {@code ModelField} for a given {@code ModelClass}. | ||
* The list will contain all fields defined on the class and on its parents, | ||
* excluding any field flagged as being xml transient. | ||
*/ | ||
public List<ModelField> xmlFields( ModelClass modelClass ) | ||
{ | ||
List<ModelClass> classes = new ArrayList<>(); | ||
// get the full inheritance | ||
while ( modelClass != null ) | ||
{ | ||
classes.add( modelClass ); | ||
String superClass = modelClass.getSuperClass(); | ||
if ( superClass != null ) | ||
{ | ||
// superClass can be located outside (not generated by modello) | ||
modelClass = modelClass.getModel().getClass( superClass, version, true ); | ||
} | ||
else | ||
{ | ||
modelClass = null; | ||
} | ||
} | ||
List<ModelField> fields = new ArrayList<>(); | ||
for ( int i = classes.size() - 1; i >= 0; i-- ) | ||
{ | ||
modelClass = classes.get( i ); | ||
Iterator<ModelField> parentIter = fields.iterator(); | ||
fields = new ArrayList<>(); | ||
for ( ModelField field : modelClass.getFields( version ) ) | ||
{ | ||
XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata( XmlFieldMetadata.ID ); | ||
if ( xmlFieldMetadata.isTransient() ) | ||
{ | ||
// just ignore xml.transient fields | ||
continue; | ||
} | ||
if ( xmlFieldMetadata.getInsertParentFieldsUpTo() != null ) | ||
{ | ||
// insert fields from parent up to the specified field | ||
boolean found = false; | ||
while ( !found && parentIter.hasNext() ) | ||
{ | ||
ModelField parentField = parentIter.next(); | ||
fields.add( parentField ); | ||
found = parentField.getName().equals( xmlFieldMetadata.getInsertParentFieldsUpTo() ); | ||
} | ||
if ( !found ) | ||
{ | ||
// interParentFieldsUpTo not found | ||
throw new ModelloRuntimeException( "parent field not found: class " | ||
+ modelClass.getName() + " xml.insertParentFieldUpTo='" | ||
+ xmlFieldMetadata.getInsertParentFieldsUpTo() + "'" ); | ||
} | ||
} | ||
fields.add( field ); | ||
} | ||
// add every remaining fields from parent class | ||
while ( parentIter.hasNext() ) | ||
{ | ||
fields.add( parentIter.next() ); | ||
} | ||
} | ||
return fields; | ||
} | ||
} |
Oops, something went wrong.