In this section we describe the formulation of the Java2Measurement transformation from the Java programs to the measurement metamodel.
5.4.1
Source and Target Metamodels
Source MetamodelThe source metamodel in the transformation is a metamodel for the Java language. Since our transformations are based on EMF metamodels we needed an EMF meta- model for Java. We choose to use the Java metamodel provided by the SpoonEMF project [ND08]. Spoon is a project that provides a core API and tool support for static analysis and generative programming in Java 5 and 6. Spoon-EMF provides an EMF compliant metamodel equivalent to the Spoon API and can be used to con- vert a complete Java implementation into a single XMI file containing an instance of the metamodel [ND08, MJCH08].
Target Metamodel
Again, the target metamodel in the transformation is the measurement metamodel presented in Appendix A.
5.4.2
The Transformation Rules
The Java2Measurement transformation was written in 249 lines of ATL code com- posed of 11 transformation rules and 29 helpers. Again several of the transfor- mation rules are reasonably straightforward to specify, since the source and target metamodels have a number of elements in common. Classes and interfaces in the Java metamodel are mapped to classes in the measurement metamodel. Elements of type “built-in” are created in the measurement metamodel from TypeReference elements of the Java metamodel where the name of the TypeReference is one of Java’s built in types e.g. float, int or the String class.
The child/parent relationship for a class in the measurement metamodel is re- solved through the superclass and superinterface relationships of that classes corresponding element in the Java metamodel. The superclass and
superinterface relationships resolve to TypeReference elements of the Java metamodel. The TypeReference element does not have a link to the Type element (e.g. class or interface) in the Java model that it references but only stores the name of the Type. These superclasses and superinterfaces of the class need to be resolved by looking at all classes and interfaces in the Java model and choos- ing the class or interface that has the same name as the name specified in the TypeReferenceelement.
Two rules are required for transforming a Field in the Java metamodel to an Attributeof the measurement metamodel. The first one is for attributes or fields that have a type that resolves to “built-in” type and the other is for those attributes that have a type that resolves to something other than a “built-in” type. The type is resolved through the TypeReference associated with the Field element. Again the TypeReference element does not have a link to the Type element in the Java model that it references but only stores the name of the Type. Therefore, the type of the attribute is resolved by examining all the classes and interfaces or all the primitive types in the Java model and choosing the class, interface or prim- itive type that has the same name as the name specified in the TypeReference element. Finally, the rules for determining the methods that reference the field or attribute are the same in both cases. This is done by examining all FieldAccess elements in the Java model and choosing those that access the field under consid- eration. Then for each of these FieldAccess elements, the method in which it occurs is resolved by traversing up the parent hierarchy until the owning method is reached.
Although the Java metamodel makes distinctions between constructors and meth- ods, both these elements are mapped to methods in the measurement metamodel. Figure 5.5 shows the transformation rule used to convert constructors of the Java metamodel to methods of the measurement metamodel along with two helpers re- quired by the transformation rule. The constructor element in the Java metamodel does not have a name attribute but this can be derived from the name of the class that owns the constructor. The isAbstract and isPublic attributes of the method are set using the isAbstract() and isPublic() helper functions. These two functions check the Modifiers association of the constructor to determine if it includes the abstract or public enumeration literals. The type of the method cre- ated in the measurement metamodel is set to be a constructor. The type of all other methods created in the measurement metamodel are identified syntactically, simi-
rule Constructor2Method { from javac : Java!CtConstructor to mm : Measurement!Method( name <- javac.Parent.SimpleName, param <- javac.Parameters, isAbstract <- javac.isAbstract(), isPublic <- javac.isPublic(), type <- # constructor ) }
-- Determines if the method in the Java model is public helper context Java!CtExecutable def: isPublic() : Boolean =
self.Modifiers->includes(# public);
-- Determines if the method in the Java model is abstract helper context Java!CtExecutable def: isAbstract() : Boolean =
self.Modifiers->includes(# abst);
Figure 5.5: Example of a transformation rule in ATL. This piece of ATL code shows
a transformation rule, Constructor2Method, and two associated helper operations called isAbstract and isPublic.
lar to how we categorised methods in the UML2ClassDiagMeasurement transfor- mation in Section 5.3. Methods are also categorised according to new, inherited, overridden, declared and implemented using the same rules as those outlined in the UMLClassDiag2Measurement transformation. Parameters are mapped to formal parameters in the measurement metamodel and their type resolved using a similar approach to how the type of an attribute is resolved.
Elements that were not present in the UMLClassDiag2Measurement transfor- mation are method invocations and calls to constructors. Invocations in the mea- surement metamodel map to invocations in the measurement metamodel only if the method being called is present in the Java model, thus ensuring the callee of the invocation can be resolved. The callee of the invocation is identified from the ExecutableReferenceelement of the invocation. However, as the Executable- Referencehas no link to the Executable element (i.e. method or constructor) that is being referenced or called, these Executable elements (methods and con- structors) need to be resolved by looking at all methods and constructors in the Java
model and choosing the correct one based on criteria such as name and parameter list which is specified in the ExecutableReference element. The caller of the invocation is identified by traversing up the parent hierarchy of the invocation to identify the method that the invoction belongs to. The type of the invocation is determined from the Static attribute of the ExecutableReference element. Calls to constructors are represented by their own entity NewClass and are only transformed to an invocation if they appear inside a method.