Skip to main content

Transmuters

Transmuters can modify the model in a structural way. They are a great tool for keeping models up-to-date or to add a complex feature.

Transmuters can be executed from the µRadiant or from command line.

Adding new Transmuters

To add a new Transmuter, create a class that implements ModelTransmuter and add @Transmutation:

@Transmutation(
element = "elements::DataElement",
description = "Some description of what the transmuter will change."
)
public class AddSomething implements ModelTransmuter<DataElementComposite> {

@Override
public void transmute(DataElementComposite dataElement, ModelTransmutationContext context) {
// Implement transmutation
}

}

Composite Builder Classes

To help with the implementation of the transmuters, you can make use of the CompositeBuilder classes. These classes provide an API to merge new changes into existing models.

Use the merge() method to update an element.

DataElementCompositeBuilder.merge(dataElement, context, de -> {
// Set the packageName to a new value
de.packageName("net.demo.new.package");

// Create a field named `foo` or update it if it already exists
de.fields(field -> {
field.name("foo");
field.isInfoField(true);
field.valueField(vf -> {
vf.valueFieldType("::String");
});
});
});

You can also merge with a Component to create new DataElements etc.

ComponentCompositeBuilder.merge(dataElement.getComponent(), context, component -> {
component.dataElements(newDataElement -> {
newDataElement.name(dataElement.getName() + "History");
});
});

Writing tests

You can use the TransmuterTester class to test transmutations.

public class AddSomethingTest {

private final ModelSpecBuilder specBuilder = new ModelSpecBuilder();
// If the test is named after the tested class, the TransmuterTester will find it automatically
private final TransmuterTester tester = TransmuterTester.forTest(this);

@Test
void testTransmute() {
// Create a model to test
DataElementComposite model = specBuilder.buildAndFind(
component("testComp",
dataElement("City")),
dataElement("testComp::CityUpdate"));

tester.testTransmute(model, de -> {
// Assert that the model has been updated
assertThat(de.getComponent().getDataElements(), hasItem(
isElement(dataElement("testComp::CityHistory"))
));
});
}
}
Public ModelSpecBuilder

The specBuilder field has been made public to allow the TransmuterTester to configure itself. It is also possible to pass the context object to the tester instead.

private final ModelSpecBuilder specBuilder = new ModelSpecBuilder();
private final TransmuterTester tester = TransmuterTester.forTest(this, specBuilder.getContext());

Creating a new transmutation project

To create a new transmutation resource project you will need to create a maven project.

Add the following dependencies to the project:

<dependencies>
<!-- Provides annotations and interfaces for the transmuters -->
<dependency>
<groupId>net.democritus.model</groupId>
<artifactId>modelTransmutations-core</artifactId>
<version>2.5.0</version>
</dependency>
<!-- Provides CompositeBuilder classes for elements -->
<dependency>
<groupId>net.democritus.model</groupId>
<artifactId>prime-builders</artifactId>
<version>2.5.0</version>
</dependency>
<!-- Provides tester class -->
<dependency>
<groupId>net.democritus.model</groupId>
<artifactId>modelTransmutations-test-support</artifactId>
<version>2.5.0</version>
<scope>test</scope>
</dependency>
</dependencies>

If not present yet, add the expansionResource goal to the <plugins> section in your pom.xml. Also make sure it has the includeClassPathDependencies flag enabled.

<plugins>
<plugin>
<groupId>net.democritus.maven.plugins</groupId>
<artifactId>expanders-maven-plugin</artifactId>
<version>${expanders-maven-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>expansionResource</goal>
</goals>
<configuration>
<includeClassPathDependencies>true</includeClassPathDependencies>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
include ClassPath Dependencies

This flag directs the expansionResource manifest generator to include a list of all compile project dependencies. This way, the expanders will fetch these dependencies when expanding. Without this, the prime-builders jar might not be present or might be the wrong version.