Custom Operators¶
If the out-of-the-box operators don’t meet your needs, you can create your own.
Setup¶
mgenerate4j uses compile-time annotation processing so you will need to enable this:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>uk.dioxic.mgenerate</groupId>
<artifactId>mgenerate-apt</artifactId>
<version>0.0.5</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
dependencies {
annotationProcessor 'uk.dioxic.mgenerate:mgenerate-apt:0.0.5'
compile 'uk.dioxic.mgenerate:mgenerate-core:0.0.5'
}
dependencies {
annotationProcessor("uk.dioxic.mgenerate:mgenerate-apt:0.0.5")
compile("uk.dioxic.mgenerate:mgenerate-core:0.0.5")
}
Basics¶
Creating a new operator is easy, in 3 simple steps:
- Create a new class
- Implement the
Resolvable
interface or extend theAbstractOperator
class - Annotate with
@Operator
@Operator
public class Hello extends AbstractOperator<String> {
@Override
public String resolveInternal() {
return "hello world!";
}
}
The annotation processor will automatically create a builder class for your operator at compile-time in the same package.
You then add the builder to the OperatorFactory
by either giving it the builder class or it’s package.
public class Main {
static {
// add single operator builder
OperatorFactory.addBuilder(HelloBuilder.class);
// add all operator builders under this package signature
OperatorFactory.addBuilder("com.example");
}
}
Your custom operator can then be used just like any other operator.
{
"greeting": "$hello"
}
{
"greeting": "hello world!"
}
Aliasing¶
By default, the operator name will be the same as the lower-case class name but it can be given one or more aliases
by specifying the value attribute on the @Operator
annotation.
@Operator({"greet", "sayhello"})
public class Hello extends AbstractOperator<String> {
@Override
public String resolveInternal() {
return "hello world!";
}
}
{
"greeting": "$hello",
"greeting2": "$greeting",
"greeting3": "$sayhello"
}
{
"greeting": "hello world!",
"greeting2": "hello world!",
"greeting3": "hello world!"
}
Arguments¶
If you want to pass arguments into your operator you can annotation either a class-level variable or method with
the @OperatorProperty
annotation. These will need to be either package-protected or public.
If the property is required, set the required attribute on the annotation.
@Operator
public class Greet extends AbstractOperator<String> {
@OperatorProperty(required = true)
String name;
@Override
public String resolveInternal() {
return "hello " + name + "!";
}
}
{ "greeting": { "$greet": "Bob" } }
{ "greeting": "hello Bob!" }
```
Dynamic Arguments¶
We can pass another operator into our customGreeting
property and this will work fine, however, in this mode,
the input operator will be hydrated only once. So, every document generated will have the same value.
{ "greeting": { "$greet": "$first" } }
{ "greeting": "hello Bob!" }
{ "greeting": "hello Bob!" }
{ "greeting": "hello Bob!" }
If we want the input operator to be resolved separately for every generated document then we need the input variable
to be a Resolvable
type and resolve it in our resolveInternal
method.
@Operator
public class Greet extends AbstractOperator<String> {
@OperatorProperty(required = true)
Resolvable<String> name;
@Override
public String resolveInternal() {
return "hello " + name.resolve() + "!";
}
}
{ "greeting": { "$greet": "$first" } }
{ "greeting": "hello Bob!" }
{ "greeting": "hello Mike!" }
{ "greeting": "hello Stavros!" }
Default Values¶
We can set defaults for our operator properties. If we are using Resolvable
types then we need to wrap them using the Wrapper
helper.
@Operator
public class Greet extends AbstractOperator<String> {
@OperatorProperty
String greeting = "hello";
@OperatorProperty
Resolvable<String> name = Wrapper.wrap("Bob");
@Override
public String resolveInternal() {
return greeting + " " + name.resolve() + "!";
}
}
{ "greeting": "$greet"
{ "greeting": { "$greet": { "greeting": "bonjour", "name": "Stavros" } } }
{ "greeting": "hello Bob!" }
{ "greeting": "bonjour Stavros!" }