How do I transmute extended or generalized elements?
The standard CompositeBuilder.merge() pattern works directly against an ElementClass's own attributes and
references. It doesn't know about elements attached through a Model Extension or a subclass of an abstract superclass
. Those relationships aren't visible to a builder generated from the parent's own metamodel. Two situations need a
different approach.
Transmuting into a Model Extension
If the target metamodel is extendable, like elements::Component, you can attach your own elements as children,
but the composite builder for Component has no knowledge of your metamodel, since the component doesn't (and
shouldn't) know about extensions defined elsewhere. To transmute into an extension, the metamodel providing the
extension needs to supply an adapter for the builder.
For example, the Workflow metamodel extends Component and provides a WorkflowCompositeExtensionAdapter, which
lets a transmuter merge changes into workflow elementsFlow Element (FlowElement). [Deprecated ] A deprecated process modeling construct describing state transitions targeting a status field on a DataElement. through the normal ComponentCompositeBuilder:
ComponentCompositeBuilder.merge(flowElement.getComponent(), context, component -> {
component.extensions(new WorkflowCompositeExtensionAdapter(), workflow -> {
workflow.name("ExampleFlow");
});
});
If you're defining your own Model Extension, provide a matching CompositeExtensionAdapter alongside it so other
transmuters (including your own) can merge into it the same way.
Transmuting a subclass of an abstract element
The same problem shows up with generalization: a reference may target an abstract superclass, with the concrete subclass defined in another metamodel — so the builder generated for the superclass has no knowledge of that subclass either.
For example, SimpleValueType has a reference to the abstract ValueTypeRestriction element. Since
ValueTypeRestriction isn't sealed, other metamodels can add their own subtypes, such as a DateInMonth
restriction that only accepts dates in a given month. As with extensions, the metamodel providing the subclass
supplies an adapter (here, DateInMonthCompositeAdapter) so transmuters can safely merge instances of it onto the
superclass reference:
SimpleValueTypeCompositeBuilder.merge(simpleValueType, context, valueType -> {
valueType.restrictions(new DateInMonthCompositeAdapter(), dateInMonth -> {
dateInMonth.month("april");
});
});