Eine Type-Mapping Datei besteht aus 4 Abschnitten:
Angabe einer oder mehrerer Type-Mapping Dateien die eingebunden bzw. erweitert werden soll
Angabe wie Type-Modifikatoren behandelt werden
Angabe wie primitive Typen gemappt werden
Abbildung von externen Typen
Das folgende Listing zeigt den schematischen Aufbau der Type-Mapping Datei.
<?xml version="1.0" encoding="UTF-8"?>
<tns:typeMapping xmlns:tns="http://www.genesez.de/typemapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<tns:include>
<tns:file>
de/genesez/platforms/common/typemapping/typemapping.xml
</tns:file>
</tns:include>
<tns:multiValuedTypes> ... </tns:multiValuedTypes>
<tns:primitiveTypes> ... </tns:primitiveTypes>
<tns:externalTypes> ... </tns:externalTypes>
</tns:typeMapping>Für die Type-Mapping Dateien gibt es ein XML Schema welches zur Validierung genutzt wird. Das Schema wird immer automatisch aus dem Classpath (Ressource: de/genesez/platforms/common/typemapping/typemapping.xsd) geladen und muss nicht explizit in der XML Datei per schemaLocation angegeben werden!
Angabe einer oder mehrerer Type-Mapping Dateien mit einem Identifier der genutzt wird um die referenzierten Type-Mapping Dateien aus dem Classpath zu laden. Alle in dieser Datei definierten Mappings werden eingebunden.
<tns:include>
<tns:file>
de/genesez/platforms/common/typemapping/typemapping.xml
</tns:file>
</tns:include>In diesem Abschnitt wird definiert, wie Typen unter Berücksichtigung der Typ-Modifikatoren abgebildet werden. Dazu stehen die beiden optionalen Attribute unique und ordered bereit.
<tns:multiValuedType ordered="true" unique="true">
<tns:default>java.util.Set</tns:default>
</tns:multiValuedType>Die beiden Attribute sind optional da in der UML Standardwerte festgelegt sind: unique == true und ordered == false. Eine andere Möglichkeit der Angabe für das obige Mapping unter Nutzung der Standardwerte ist die folgende:
<tns:multiValuedType ordered="true">
<tns:default>java.util.Set</tns:default>
</tns:multiValuedType>Für den Typ-Modifikator unique ist kein Wert angegeben wodurch der Standartwert aus der UML genutzt wird. Da dieser true ist entsteht ein identisches Mapping wie bei der Angabe beider Modifikatoren.
Um Mappings für primitive und externe Typen zu erstellen wird die gleiche Syntax genutzt:
<tns:type from="boolean">
<tns:to> boolean </tns:to>
</tns:type>Das Element type steht für eine Type-Mapping Definition. Mit dem from Attribut wird der im Modell verwendete Name des abzubildenden Typs angegeben. Mit dem Element to wird der Name des Typs in der Zielsprache angegeben auf den der Typ abgebildet wird. Im Beispiel oben wird der im UML-Metamodell enthaltene primitive Typ Boolean auf den Typ boolean der Zielprogrammiersprache abgebildet.
Kontexte werden genutzt um die verschiedenen Verwendungsmöglichkeiten von Typen in der Zielsprache zu adressieren. Es können beliebig viele Kontext-Mappings für einen Typ angegeben werden. Jedes Kontext-Mapping stellt einen bestimmten Bereich bzw. Situation dar, in welcher ein Typ im Xpand-Template gemappt wird. Diese Kontexte werden also nicht im Modell angegeben, sondern bei dem Aufruf des Type-Mappings im Xpand-Template.
Zur Verringerung der Kopplung in Quellcode werden z.B. Attributen mit dem Interface-Typ definiert und nur in deren Initialisierung die gewünschte konkrete Implementierung verwendet. Um solche Probleme zu Adressieren können die Standardmappings mit Kontext-bezogenen Mappings erweitert werden.
Das folgende Beispiel zeigt ein Multi-Value Type-Mapping, das zwischen Interface-Typ und konkreter Implementierung unterscheidet:
<tns:multiValuedType ordered="true">
<tns:default> java.util.Set </tns:default>
<tns:context name="Implementation">
java.util.LinkedHashSet
</tns:context>
</tns:multiValuedType>In der Programmiersprache Java könnte das obige Mapping in folgendem Quellcode resultieren:
java.util.Set<String> strings = new java.util.LinkedHashSet<String>();
Für den Typ der Variablen wird der Standardtyp (Interface-Typ) genutzt. Nur bei der Initialisierung der Variablen wird die konkrete Implementierung verwendet. Dies resultiert in einer geringeren Kopplung zu genutzten Implementierung.
Kontexte können darüber hinaus auch in Primitive Type und External Type Mappings verwendet werden. Ein Kontext kann bei Java z.B. dazu genutzt werden um die Primitiven Typen auf ihre Wrapper-Typen in Java abzubilden:
<tns:type from="boolean">
<tns:to>boolean</tns:to>
<tns:context name="Wrapper">Boolean</tns:context>
</tns:type>Dadurch ist es möglich bei einer speziellen Verwendung des Typs Boolean auf den Wrapper Typ Boolean zu mappen anstatt auf den Primitiven Typ boolean. Notwendig ist dies z.B. bei Multi-Value Typen:
java.util.Set<Boolean> bs = new java.util.LinkedHashSet<Boolean>();
Der Primitive Typ boolean kann in Java nicht als generischer Parameter verwendet werden. Deshalb muss sein Wrapper Typ genutzt werden.
Für External Type Mappings sind Kontexte u.a. in Bezug auf die Generierung von import bzw. include Statements sinnvoll:
<!-- container is the base class for custom authentication providers
from the 'PEAR::Auth' package -->
<tns:type from="Auth_Container">
<!-- default mapping is to the class name -->
<tns:to>Auth_Container</tns:to>
<!-- used to generate imports -->
<tns:context name="import">Auth/Container.php</tns:context>
</tns:type>Standardmäßig wird der Typ in dem Beispiel auf den Klassennamen abgebildet. Wird jedoch der Kontext import angegeben, wird der benötigte Teil für die PHP include Anweisung zurückgegeben.