Boilerplate code doesn't stop at builders. There is often need for Factory
, Manager
, Handler
, Wrapper
and so on, that needs to be created per object of a specific domain.
Wouldn't it be great if you could instead create a template and have the boilerplate get automatically generated for you?
There are tons of template engines out there, but they require a couple of things:
- A way to hook them into the build.
- A way to model your classes and feed them to the template.
This is complicates things enough to make writing boilerplate code seem more appealing!
Simplifying the process described above is the goal of this module....
This module introduces @TemplateTrasnformation
which accepts the path of a template and can be used to annotate any type.
Upon compilation the annotated class will be passed to the Template Context using the key model
. Then the template will be rendered
and the output will be stored inside a new source file. The path of the source file will be determined by the fully qualified name of the generated class and the standard generated source location.
To get access to the @TemplateTransformation
you need the following dependency:
<dependency>
<groupId>io.sundr</groupId>
<artifactId>transform-annotations</artifactId>
<version>${sundrio.version}</version>
</dependency>
At the moment the supported template engines are:
- Apache Velocity
- String Template
However, an api/spi is provided that allows easily connecting any other kind of template engines.
As an example let's generate a Singleton.
The first thing we need is a template:
package ${model.packageName};
public class ${model.name}Singleton {
private static ${model.name} instance;
public static synchronized ${model.name} getInstance() {
if (instance == null) {
instance = new ${model.name}();
}
return instance;
}
}
We can now use the @TemplateTransformation
to annotate any type:
@TemplateTransformation("transformation.vm")
public class SomeClass {
//some code
}
This will result in the generation of a new class called SomeClassSingleton
in the same package.
Note: The name and the package are determined by the output class.
To use Apache Velocity as the template engine, you need to add:
<dependency>
<groupId>io.sundr</groupId>
<artifactId>sundr-codegen-velocity</artifactId>
<version>${sundrio.version}</version>
</dependency>
If you prefer to have velocity and its transitive dependencies shaded into the artifact (to avoid dependency management headaches) you can use instead:
<dependency>
<groupId>io.sundr</groupId>
<artifactId>sundr-codegen-velocity-nodeps</artifactId>
<version>${sundrio.version}</version>
</dependency>
To use String Template 4 as the template engine, you need to add:
<dependency>
<groupId>io.sundr</groupId>
<artifactId>sundr-codegen-st4</artifactId>
<version>${sundrio.version}</version>
</dependency>
If you prefer to have String Template 4 and its transitive dependencies shaded into the artifact (to avoid dependency management headaches) you can use instead:
<dependency>
<groupId>io.sundr</groupId>
<artifactId>sundr-codegen-st4-nodeps</artifactId>
<version>${sundrio.version}</version>
</dependency>
There are three ways to pass your templates to the annotation:
- as local resources
- as local resources relative to the package
- as classpath resources
In this setup, you just need to put the templates under src/main/resources
and reference them as /my-template.vm
.
package your.package.here;
@TemplateTransformation("/my-template.vm")
public class MyClass {
//some code
}
Note: The leading /
is indicates that we want to try and read the template from the local root (a.k.a target/classes
). The name and the suffix of the template can be anything you choose.
In this setup, you just need to put the template under src/main/resources/<your>/<package>/<here>
. Then you can reference it realtively to your package. For example:
package your.package.here;
@TemplateTransformation("my-template.vm")
public class MyClass {
//some code
}
It can work in the same manner as described above in the local
setups. The only real difference is that the template lives in an other artifact that is present in the classpath.
In the case were we want more than one transformation per class, we can wrap them inside @TemplateTransformations
. For example:
package your.package.here;
@TemplateTransformations({
@TemplateTransformation("factory.vm"),
@TemplateTransformation("manager.vm")
})
public class MyClass {
//some code
}