Model-to-model transformation authoring

You can divide model-to-model mapping solutions into multiple mapping models in multiple mapping projects. Creating model-to-model transformations with mappings is the process of creating a mapping model, which is a model that contains rules that describe how to map the objects in one model to the objects in another model. After you create the mapping model, you can generate transformation source code that transforms a source model into a target model.

Transformation authoring prerequisites

Note: To create transformations, you must install the extensibility features, which are packaged as an optional product component. You must enable the Modeling and XML Developer capabilities.

Model-to-model transformation authoring process

The model-to-model transformation authoring process consists of the following high-level steps:
  1. You create a model-to-model transformation mapping project, also called a mapping project, that contains a mapping model. A mapping project can contain multiple mapping models. When you create a mapping project, the transformation service registers one transformation. Each transformation has one transformation provider, a transform called MainTransform, and one transform for each mapping declaration in the project.
  2. You add mapping declarations, also called maps, to the mapping model. A mapping model can contain one or more mapping declarations.
  3. You add mapping rules to the mapping declarations in a mapping model.
  4. You generate transformation source code from the mapping model or mapping models in the mapping project. The model-to-model transformation authoring tools generate one transformation for each mapping model in the mapping project. For each mapping declaration, the authoring tools generate a Java source file that implements a transform. For each move or custom mapping rule in a mapping declaration, a rule is generated in the transform source code. For each submap mapping rule in a mapping declaration, a content extractor is generated in the transform source code.

Model-to-model transformation mapping projects

Model-to-model transformation mapping projects, also called mapping projects, are Eclipse plug-ins that extend the extension point named com.ibm.xtools.transform.core.transformationProviders. By creating model-to-model transformations in transformation mapping projects, you can specify how elements in the selected source and target models, or metamodels, are related, instead of creating code that represents the implementation details of the transformation.

A mapping project can contain more than one mapping file, which is also called a mapping model. You can iteratively generate transformation source code when you modify the mapping model. When you generate the transformation source code, one externally visible transform, called MainTransform, is registered automatically, and the Java source code for a transform is generated for each mapping declaration in the mapping model.

You can specify one or more source and target metamodels when you create a mapping project. You can specify metamodels, which have .ecore as a file name extension, or UML profiles, which have .epx or .uml as a file name extension. If you specify source and target metamodels when you create a project, the necessary dependencies are added to the plug-in manifest file automatically. If you add the metamodels by using the commands in the editor area after you create the mapping project, you must add any new required dependencies to the plug-in manifest file.

Mapping models

Mapping models, also called mapping files, are instances of Eclipse Modeling Framework (EMF) metamodels, also called Ecore models, that contain references to the metamodels that are being mapped. When you create a mapping project, the authoring tools create a mapping model in the project by using the input and output model or models that you specify. A mapping project contains at least one mapping model. A mapping model has .mapping as a file name extension. Creating multiple mapping models in a project encourages the reuse of maps in other mapping projects. This functionality is useful for large-scale mapping solutions, where multiple mapping models exist in multiple mapping projects.

Mapping models are stored and serialized as XML files. The Problems view displays detailed error information about mapping models. In this view, double-click an item to open the mapping model in a text editor and view the line that contains the error. This method of troubleshooting is often easier than troubleshooting by viewing the mapping model in the editor area.

Mapping declarations

A mapping declaration, also called a map, specifies how to create or update an output object for a given input object. Each mapping declaration specifies an input type and an output type, which you select from the metamodels that you add to the mapping model. A mapping model can contain multiple mapping declarations.

The purpose of creating a map is to assign values to a target, based on the values in a source. A map between elements establishes the correspondence between their attributes, which permits the exchange of data between them. Most maps provide the ability to further manipulate the data between the source and target. For example, you might choose to specify calculations or make other modifications to the data by creating custom code, which enables you to assign values to the target.

Mapping declarations can contain abstract output objects. Such mapping declarations can only be inherited, extended, or referenced in a submap mapping rule whose target attribute contains a containment property that is set to false. Such target attributes might be populated with references to objects that are created by a mapping declaration that inherits from the mapping declaration that is specified in the submap mapping rule. You might use a mapping declaration that specifies an abstract output object to simplify the creation of object references.

Mapping declarations typically follow a naming convention of x2y, where x represents the input object type and y represents the output object type. For example, a mapping declaration named Package2EPackage specifies a mapping declaration that has Package as an input object, and EPackage as an output object.

When you generate the transformation source code, the transformation service generates a Java source file for each mapping declaration in a mapping model, which implements a transform.

Mapping declarations contain one or more mapping rules.

Mapping declaration inheritance

Mapping declarations can inherit from other mapping declarations. The inherited and inheriting mapping declarations do not have to be defined in the same mapping model. The inheriting input and output objects must be subtypes, but not necessarily proper subtypes, of the input and output objects in the inherited mapping declaration. The inheriting mapping declaration inherits all the mappings defined in, or inherited by, the inherited mapping declaration. The mapping rules in the inherited mapping declaration become part of the inheriting mapping declaration; however, you can create custom mapping rules to override those in the inherited mapping declaration. You can also create additional mapping rules in the inheriting mapping declaration. The transform that is generated from an inheriting mapping declaration extends the transform that is generated from the inherited mapping declaration.

Mapping rules

Mapping rules, also called mappings, specify how to assign a value to an attribute of an output object, according to the values of the attributes of an input object.

You can create the following types of mapping rules between the attributes of input and output objects:
Move
A move, also called a simple mapping rule, is the most basic type of mapping rule. The input and output attributes must be compatible data types: the Ecore EDataTypes of the input and output attributes must be equal, or the data type of the output attribute is a String and the data type of the input attribute can be serialized. Both, or neither, of the input and output attributes have multiple values. For example, select this option if an attribute of the output object is a String and an attribute of the input object can be converted to a String without custom code. This type of mapping rule supports a mapping between one source element or attribute and one target element or attribute. The transformation source code that is generated for a move mapping rule implements a rule that copies the value of one input attribute to one output attribute.
Submap
A submap is an invocation of one map from within another map. The submap being invoked can, but need not, be defined in the same mapping file as the map that invokes it. A submap enables you to map a complex type in the input model to a complex type in the output model. The submap that you create can invoke a map that exists in any mapping file. For example, consider a mapping model called NewMappingModel, and a mapping model called OriginalMappingModel that contains a map called Package2Package. To create a map in the NewMappingModel that specifies a mapping between an input package and an output package, whose behavior is the same as the Package2Package map in the OriginalMappingModel, you can specify the mapping file for the OriginalMappingModel. Defining submaps in separate mapping files encourages the reuse of maps; however, creating multiple mapping files might increase project maintenance. Submaps can also include other submaps, which results in a hierarchical structure.

You can also create submap mapping rules between the input objects and output objects in a mapping declaration.

Submap mapping rules support the following types of mappings:
  • 1-to-1 mappings between input objects and output objects, or between the attributes of the input and output objects
  • 1-to-m or m-to-1 mappings between attributes of the input and output objects
  • m-to-n mappings between attributes of the input and output objects
If the submap rule specifies a 1-to-m mapping, the generated transform appends an object from a singleton attribute to a list; for an m-to-1 mapping, the transform extracts an object from a list and inserts it into a singleton attribute.

For each submap in a mapping declaration, an extractor named getInputFeatureToOutputFeature_UsingMap_Extractor is generated in the containing transform, where InputFeature represents the name of the input attribute, OutputFeature represents the name of the output attribute, and Map represents the name of the mapping declaration.

Custom
This mapping type enables you to specify custom code that calculates the value of an output property. For example, select this mapping type to set the value of a property in the output object as equal to the concatenation of multiple input object properties.

You can specify semantic refinements by using the Object Constraint Language (OCL) API that Eclipse provides.

Custom mapping rules support the following types of mappings:
  • 1-to-n mappings between input and output objects, or between attributes of the input and output objects
  • m-to-n mappings between input and output objects, or between attributes of the input and output objects
  • m-to-1 mappings, where m-to-1 represents one of the following mappings:
    • A mapping from a single input attribute, whose multiplicity is set to m, to a single output attribute, whose multiplicity is set to 1
    • A mapping from multiple input attributes to a single output attribute
    • A mapping from multiple input objects to a single output object
Inherited maps
An inheriting mapping declaration inherits the mapping rules that are defined in the inherited mapping declaration. You can override inherited mapping rules by defining a mapping rule that has the following qualities:
  • The input object property and output object property are the same as the inherited mapping rule.
  • The overriding and inherited mapping rules are submap mappings that have matching extractors, or the overriding and inherited mapping rules are both move mappings or custom mappings.
If you create an inherited maps mapping rule, you must specify the mapping declaration that contains the mapping rules that you want to inherit. You cannot specify more than one inherited map in a mapping declaration.

An inherited mapping rule, and the rule or extractor generated from that mapping, maintains the same relative position in the processing order as the overridden mapping rule and its generated rule or extractor.

For each move or custom mapping rule in a mapping declaration, a rule is added to the generated transformation source code. For each submap mapping rule, a content extractor is generated in the transformation source code.

When you create a mapping rule, its type is determined by the input and output attributes that you select. For example, if the input and output attributes are compatible primitive types, such as strings or integers, a move mapping rule is specified. If the input and output attributes are complex types, a submap rule is specified. If neither move nor submap are appropriate mapping rule types, a custom mapping rule is specified.

You can also create a submap, custom, or inherited maps mapping rule between an input object and an output object.

Submap mapping rule behavior

The characteristics of output objects and the containment properties of attributes in an output object determine the behavior of submap mapping rules.

Submap structure
A mapping declaration can contain one or more submap definitions. Each submap is defined by a set of values, as in the following example: (InputFeature, OutputFeature, (Map, InputElement, OutputElement)), where the values represent the items in the following table:
Item Representation
InputFeature The compartment in the input object that is connected to the submap element
OutputFeature The compartment in the output object that is connected to the submap element
Map The mapping declaration that the submap applies when the generated transform runs
InputElement The input object that the Map mapping declaration specifies
OutputElement The output object that the Map mapping declaration specifies

When you generate transformation source code for a mapping model, for each mapping declaration, the authoring tools generate a transform named MapTransform. For each submap in a mapping declaration, the authoring tools generate a content extractor named getInputFeatureToOutputFeature_UsingMap_Extractor in the transform.

When a model-to-model transformation runs, it generates either objects or references to generated objects, depending on the feature settings in the metamodel. If the transformation generates objects, it records identifying information about those objects in a hash map. The transformation resolves references to objects during post-processing, based on the hash map.

Submap semantics

The Ecore or UML metamodel element that you specify as the output object in a mapping declaration can be abstract or concrete. You can instantiate concrete elements, but not abstract elements.

The features, also known as attributes, of an output object can contain or refer to other Ecore or UML objects. If an object contains another object, the contained object is deleted when the containing object is deleted. If an object references another object, deleting the reference or deleting the owner of the reference does not delete the referenced object.

The following table lists the behavior of submap mapping rules depending on the characteristics of the output object and output attributes.

Type of output object Type of containment or reference in the output attribute Submap behavior
Abstract Abstract or concrete containment This type of submap is not supported because the MapTransform transform cannot create objects and, therefore, cannot insert objects into the OutputFeature collection.
Abstract or concrete Abstract or concrete reference After processing all other rules and extractors, the transformation processes this type of submap by completing the following steps:
  • Searches the hash map for target objects by using a search key equal to (MapTransform+InputItem), where InputItem represents an object in the InputFeature collection.
    Note: An exact match in the search is not required. For example, a search key equal to (MapTransform+InputItem) returns records whose keys equal (MapTransform*+InputItem), where MapTransform* represents the set of all transforms that inherit from the MapTransform transform.
    • If the search returns one target object named TargetObject, the transformation inserts a reference to TargetObject in the appropriate OutputFeature collection.
    • If the search returns multiple candidate objects, the transformation applies the submap output filter, if defined, to select one object; then, the transformation inserts a reference to TargetObject in the appropriate OutputFeature collection. If the submap does not define an output filter, the transformation selects the first candidate object in the list of search results and inserts a reference to TargetObject in the appropriate OutputFeature collection.
    • If the search does not return a result, the transformation logs an error and displays a message.
Concrete Abstract or concrete containment For each object InputItem in the InputFeature collection, the transformation completes the following steps:
  • Runs the MapTransform transform to create an object TargetObject of type OutputElement
  • Inserts an instance of object TargetObject into the OutputFeature collection
  • Records the action in a hash map, whose key has the following format: (MapTransform+InputItem->TargetObject)
Example

The following example explains how a transformation resolves references to output objects during post-processing.

In this example, a mapping model contains the following items:
  • A mapping declaration named Classifier2Classifier that specifies a UML classifier as the input object and the output object
  • A mapping declaration named Class2Class that specifies a UML class as the input object and the output object

    This mapping declaration defines an inherited maps mapping rule between the input and output object. The mapping rule specifies that this mapping declaration inherits from the Classifier2Classifier mapping declaration.

In the generated transformation source code, notice that the transform named Class2ClassTransform inherits from the transform named Classifier2ClassifierTransform:
public class Class2ClassTransform extends Classifier2ClassifierTransform {

...
}

Because a classifier is an abstract type, the Classifier2ClassifierTransform transform cannot create objects. However, the Class2ClassTransform transform can create objects, even though a class inherits from a classifier.

If you run the transformation on a source model that contains an input class named ClassA, the Class2ClassTransform transform generates an output class named ClassB. To record the creation of ClassB, the Class2ClassTransform transform creates a hash map record whose key equals (Class2ClassTransform+ClassA->ClassB).

If the transformation searches the hash map for a record whose key equals (Classifier2ClassifierTransform+ClassA), the record whose key equals (Class2ClassTransform+ClassA) is returned in the search results because the Class2ClassTransform transform inherits from the Classifier2ClassifierTransform transform.

Impact of iterative development on mapping rules

In an iterative development environment, changes might occur to the input or output metamodels that you specify in a mapping model. These changes might also affect the input and output objects that you specify in a mapping declaration, and might invalidate the corresponding mapping rules. If this situation occurs, you must refactor the mapping rules in the mapping declaration. When you refactor mapping rules, you can specify whether the mapping editor should perform a best-effort mapping between the changed models and the existing mapping rules, whether to leave the existing mapping rules disconnected, or whether to delete the invalid mapping rules. The following types of changes might require you to refactor a mapping declaration:
  • The URI of a metamodel is changed
  • Metamodels that contain the source or target objects specified in the mapping model are added or removed
  • Input and output objects in a mapping declaration are changed or removed
  • Attributes of an object in the source or target model or metamodel are changed or removed
  • The containment or multiplicity properties of input or output object attributes are changed

For example, consider a mapping model called OriginalMappingModel that contains a mapping declaration called Package2Package. The input object in the mapping declaration is in an input metamodel called MyPackageDefinition, and the output object in the mapping declaration belongs to an output metamodel called MyOtherPackageDefinition. The mapping declaration contains a move mapping rule that connects two String attributes that are both called PackageName. If the URI of the MyPackageDefinition metamodel changes, the Package2Package mapping rule becomes invalid. The next time that you open the mapping model, the Problems view displays error messages, and in the mapping editor area, an error adornment is displayed on the invalid mapping declaration. You must specify a correct input object and specify how the mapping editor should refactor the existing mapping rules.

After you refactor the mapping rules, you can continue to refine the mapping model and regenerate transformation code.

Merge support and options

If you plan to merge the transformation output into an existing model, the target metamodel must declare a CompareMerge content type extension. If the transformation output is a UML model, the content type extension is defined by default, and you do not have to configure merge support. If the metamodel of the target model does not declare a CompareMerge extension, the transformation overwrites the target model.

Transformation extensibility

When you generate transformation code, the @generated tag is added to the comments of Java elements such as classes, attributes, and operations. The tag informs the code generator that a specific code element is under its control, which enables the code generator to update the code for the Java element if changes occur to the mapping model. You can modify and extend the transformation code by editing or removing the @generated tag of the Java element that you want to change.


Feedback