Transformations come in two different flavors: model-to-model and model-to-text transformations.
Model-to-model transformations are written using ATL, the ATLAS transformation language. You will find documentation material about it on the ATL homepage on Eclipse.org. Click on the Documentation link on that page to find The ATL Starter's Guide and The ATL User Manual.
The second form of transformations, model-to-text transformations, are written in the MOFScript language. You will find documentation material about it on the MOFScript Home page on Eclipse.org. Click on the Documentation link on that page to find the MOFScript User guide.
Look at this very small model which we will now transform, step by step:

As you can see, this is a UML model. First of all, we will apply a transformation from the UML to the EnterpriseApp metamodel. EnterpriseApp is a small metamodel that basically contains the metaclasses Service and Entity. We will now transform each UML class with the stereotype <<Service>> to a Service, the same with entities. This is a snippet from UML2EnterpriseApp.atl:
helper context UML2!Element def : hasStereotype(s : String) : Boolean
self.getAppliedStereotypes()->exists(sttype | sttype.name = s);
helper context UML2!Element def : isService() : Boolean =
self.oclIsTypeOf(UML2!Class) and self.hasStereotype('Service');
rule UMLServiceToEnterpriseAppService
{
from class : UML2!Class (class.isService())
to out : EnterpriseApp!Service (
name <- class.name,
methods <- class.ownedOperation,
sourceReferences <- class.clientDependency
)
}After this first transformation step, a Service looks like this (at least if you save the intermediate EnterpriseApp model in XMI which you would only do while debugging your transformation):
<ownedElements xsi:type="eapp:Service" xmi:id="a12" sourceReferences="a22 a21"
name="RegistryService">
<methods xmi:id="a13" name="register" instanceScope="true" returnType="a19">
<parameters xmi:id="a14" name="owner" type="a7"/>
<parameters xmi:id="a15" name="car" type="a10"/>
</methods>
</ownedElements>Next step: Let's transform this Service into a SpringBean, using the following snippet from EnterpriseApp2Spring.atl:
rule EnterpriseAppServiceToSpringBean
{
from service : EnterpriseApp!Service
to out : Spring!SpringBean (
name <- service.name
,methods <- service.methods
,sourceReferences <- service.sourceReferences
,package <- service.package
,purpose <- 'SpringService'
)
}The result is not spectacular at all:
<ownedElements xsi:type="spring:SpringBean" xmi:id="a7" name="RegistryService"
purpose="SpringService" sourceReferences="a23 a24">
<methods xmi:id="a8" name="register" instanceScope="true" returnType="a19">
<parameters xmi:id="a9" name="owner" type="a15"/>
<parameters xmi:id="a10" name="car" type="a12"/>
</methods>
</ownedElements>The interesting step comes in the next transformation which turns a Spring bean into an interface, a base class and an implementation class, all in the OOP (object oriented programming) metamodel, ready to be transformed to Java code. Let's have a look at this snippet from the Spring2OOP.atl transformation:
rule SpringBeanToClassAndInterface
{
from bean : Spring!SpringBean
to interface : OOP!Interface (
name <- bean.name
,methods <- bean.methods -- TODO: need to mark them as abstract
,package <- bean.package
)
, baseClass : OOP!Class (
name <- bean.name + 'Base'
,methods <- bean.methods -- TODO: need to mark them as abstract
,properties <- bean.sourceReferences
,package <- bean.package
,purpose <- bean.purpose + 'Base'
)
, implementationClass : OOP!Class (
name <- bean.name + 'Impl'
,methods <- bean.methods
,package <- bean.package
,purpose <- bean.purpose + 'Impl'
)
}This pretty cool rule generates one interface and two classes. The result looks like this, ready to be transformed to Java code:
<ownedElements xsi:type="oop:Interface" xmi:id="a10" name="RegistryService"
methods="a27"/>
<ownedElements xsi:type="oop:Class" xmi:id="a11" name="RegistryServiceBase"
purpose="SpringServiceBase" methods="a27">
<properties xmi:id="a12" name="carDao" visibility="public" type="a15"/>
<properties xmi:id="a13" name="personDao" visibility="public" type="a7"/>
</ownedElements>
<ownedElements xsi:type="oop:Class" xmi:id="a14" name="RegistryServiceImpl"
purpose="SpringServiceImpl" methods="a27"/>This is the way to get the generated source code. The workflow feeds the final model (instance of the OOP metamodel) into a model-to-text transformation in the MOFScript language. Each instance of Class is transformed into source code using the following rules in SpringDao2Java.m2t and OOP2Java.m2t:
// get the name of the directory where DAOs should be generated
var daoOutputPath = namespaceProperty("SpringHibernate", "daos");
// this will generate code for DAO classes, only!
oop.objectsOfType(oop.Class)
->forEach(cl: oop.Class | cl.purpose = "SpringDaoBase"
or cl.purpose = "SpringDaoImpl")
{
super.mapClass2(cl, daoOutputPath);
}
module::mapClass2(cl: oop.Class, outputPath: String)
{
var fileName : String = outputPath;
if (cl.package != null)
{
fileName += "/" + fullyQualifiedPackageName(cl.package, "/");
}
fileName += "/" + cl.name + ".java";
log ("Generating " + fileName + " ...");
file (fileName);
cl.mapClass();
}
oop.Class::mapClass()
{
if (self.package != null)
{
'package ' fullyQualifiedPackageName(self.package, ".") ';' nl(2)
}
'public class ' self.name ' {' nl
nl
self.properties->forEach(p:oop.Property)
{
p.mapPropertyField()
}
self.properties->forEach(p:oop.Property)
{
p.mapPropertyGetterAndSetter()
}
self.methods->forEach(m:oop.Method)
{
m.mapMethod()
}
'}' nl
nl
}So, at the end, we have got several *.java output files. This is what we wanted to have, right? :-)