The abstraction layer on API basis is called a type system. It provides access to built-in types and different registered metamodel implementations. These registered metamodel implementations offer access to the types they provide. The first part of this documentation describes the type system. The expression sub-language is described afterwards in the second part of this documentation. This differentiation is necessary because the type system and the expression language are two different things. The type system is a kind of reflection layer, that can be extended with metamodel implementations. The expression language defines a concrete syntax for executable expressions, using the type system.
The Java API described here is located in the org.eclipse.xpand.type package and is a part of the subproject core.expressions.
Every object (e.g. model elements, values, etc.) has a type. A type contains properties and operations. In addition it might inherit from other types (multiple inheritance is also possible, depending on the underlying meta-meta-model).
Types have a simple name (e.g. String)
        and an optional namespace used to distingish between two types with
        the same name (e.g. my::metamodel). The
        delimiter for name space fragments is a double colon
        "::". A fully qualified name looks like this:
        
my::fully::qualified::MetaType
The namespace and name used by a specific type is defined by the
        corresponding MetaModel
 implementation. The EmfMetaModel
, for instance, maps
        EPackages to namespace and
        EClassifiers to names.  Therefore, the name of the Ecore element
        EClassifier is called:
ecore::EClassifier
If you do not want to use namespaces (for whatever reason), you can always implement your own metamodel and map the names accordingly.
The built-in type system also contains the following collection
        types: Collection,
        List and Set. Because
        the expressions language is statically type checked and we do not like
        casts and ClassCastExceptions, we introduced
        the concept of 
parameterized types
. The type
        system does not support full featured generics, because we do not need
        them.
The syntax is:
Collection[my::Type] List[my::Type] Set[my::Type]
Each type offers features. The type (resp. the metamodel) is responsible for mapping the features. There are three different kinds of features:
Properties
Operations
Static properties
Properties are straight forward: They have a name and a type. They can be invoked on instances of the corresponding type. The same is true for Operations . But in contrast to properties, they can have parameters. Static properties are the equivalent to enums or constants. They must be invoked statically and they do not have parameters.
As mentioned before, the expressions framework has several built-in types that define operations and properties. In the following, we will give a rough overview of the types and their features. We will not document all of the operations here, because the built-in types will evolve over time and we want to derive the documentation from the implementation (model-driven, of course). For a complete reference, consult the generated API documentation.
Object defines a couple of basic
        operations, like equals(). The property
        metaType provides access to Xpand's type for that Object. Every type
        has to extend Object.
The Void type can be specified as the
        return type for operations, although it is not recommended, because
        whenever possible expressions should be free of side effects whenever
        possible. The only possible value is null.
        Sometimes it might be useful to use Void as an
        parameter type, if you want to be able to call a function for
        different argument types and also supply a valid implementation when
        the function is invoked with null.
The type system doesn't have a concept data type. Data types are
        just types. As in OCL, we support the following types:
        String, Boolean,
        Integer, Real.
        
String
: A rich and convenient
              String library is especially important
              for code generation. The type system supports the '+' operator
              for concatenation, the usual
              java.lang.String operations
              (length(), etc.) and some special
              operations (like toFirstUpper(),
              toFirstLower(), regular expressions,
              etc. often needed in code generation templates).
Boolean
: Boolean offers the usual
              operators (Java syntax): &&, ||, !, etc.
Integer
 and Real
: Integer and
              Real offer the usual compare operators
              (<,>,<=,>=) and simple arithmetics (+,-,*,/). Note
              that 
Integer extends
              Real!
The type system has three different Collection types.
        Collection
 is the base type, it provides several operations known
        from java.util.Collection. The other two types
        (List
, Set
) correspond to their
        java.util equivalents, too.
The type system describes itself, hence, there are types for the
        different concepts. These types are needed for reflective programming.
        To avoid confusion with metatypes with the same name (it is not
        unusual to have a metatype called Operation,
        for instance) we have prefixed all of the types with the namespace
        xpand2. We have:
xpand2::Type
xpand2::Feature
xpand2::Property
xpand2::StaticProperty
xpand2::Operation
You should be aware that if you name a type by name in an
        expression the object you get is in fact an
        xpand2::Type. A common use case is to prove
        that an object is of some type or its subtype, using the
        instanceOf() operation or exactly of one
        type.
// results to true, if the result of someExpression is of type MyType or its subtypes MyType.isInstance(someExpression) // results to true, if the result of someExpression is exactly of type MyType someExpression.metaType == MyType
Note that this should be only used when really required. The recommended way to handle alternative implementations for a type hierarchy is using Multiple Dispatch.
By default, the type system only knows the built-in types. In order to register your own
      metatypes (e.g. Entity or
      State), you need to register a respective
      metamodel implementation with the type system. Within a metamodel
      implementation the 
Xpand
 type system elements
      (Type, Property,
      
 Operation) 
 are mapped to an arbitrary other type system (e.g. Java
      reflections, Ecore or XML Schema).
For instance, if you want to have the following JavaBean act as a metatype (i.e. your model contains instances of the type):
public class Attribute {
   private String name;
   private String type;
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public String getType() {
      return type;
   }
   public void setType(String type) {
      this.type = type;
   }
}
You need to use the JavaMetaModel
         implementation which uses the ordinary Java reflection
        layer in order to map access to the model.
So, if you have the following expression in e.g. Xpand :
myattr.name.toFirstUpper()
and myattr is the name of a local variable
        pointing to an instance of Attribute. The
        
Xpand
 type system asks the metamodel
        implementations, if they 'know' a type for the instance of Attribute.
        If you have the JavaMetaModel registered it
        will return an xpand2::Type which maps to the
        underlying Java class. When the type is asked if it knows a property
        'name', it will inspect the Java class using the
        Java reflection API.
The JavaMetaModel implementation shipped with
        
Xpand
 can be configured with a strategy
        [GOF95-Pattern] in order to control or change the mapping. For
        instance, the JavaBeansStrategy maps getter and
        setter methods to simple properties, so we would use this strategy for
        the example above.
You should know that for each Metamodel
        implementation you use at runtime, you need to have a so
        called MetamodelContributor extension for the
        plugins to work with. If you just use one of the standard metamodel
        implementations (EMF, UML2 or Java) you don't have to worry about it,
        since 
Xpand
 is shipped with respective
        MetamodelContributors (see the corresponding docs for details). If you
        need to implement your own
        MetamodelContributor
 you should have a look at the Eclipse plug-in reference
        doc.
You need to configure your Xpand language components with the respective metamodel implementations.
A possible configuration of the Xpand2
        generator component looks like this:
<component class="org.eclipse.xpand2.Generator">
   <metaModel class="org.eclipse.type.emf.EmfMetaModel">
      <metaModelPackage value="my.generated.MetaModel1Package"/>
   </metaModel>
   <metaModel class="org.eclipse.type.emf.EmfMetaModel">
      <metaModelFile value="my/java/package/metamodel2.ecore"/>
   </metaModel>
   ...
</component>
In this example the EmfMetaModel
        implementation is configured two times. This means that we want to use
        two metamodels at the same time, both based on EMF. The
        metaModelPackage property is a property that is
        specific to the EmfMetaModel (located in the
        org.eclipse.xtend.typesystem.emf plugin). It
        points to the generated EPackages interface.
        The second meta model is configured using the Ecore file. You do no
        need to have a generated Ecore model for 
Xpand
 in
        order to work. The EmfMetaModel works with
        dynamic EMF models just as it works with generated EMF models.
Note that is recommended to prefer the
        EmfRegistryMetaModel instead of the
        EmfMetaModel, although
        EmfMetaModel is derived from the
        EmfRegistryMetaModel. Further it is recommended
        to use platform URIs (see API
        Doc URI) to refer to EMF resources.
The use of platform URIs in the workflow requires setting up EMF
        for standalone execution with the
        StandaloneSetup class from the
        org.eclipse.emf.mwe.utils plugin. Further,
        StandaloneSetup is used to register known EMF packages. An equivalent
        workflow configuration for the sample above would look like
        this:
<bean class="org.eclipse.emf.mwe.utils.StandaloneSetup"> <platformUri value=".."/> <registerGeneratedEPackage value="my.generated.MetaModel1Package"/> <registerEcoreFile value="platform:/resource/my/java/package/metamodel2.ecore"/> </bean> ... <component class="org.eclipse.xpand2.Generator"> <metaModel class="org.eclipse.type.emf.EmfRegistryMetaModel"/> ... </component>
The StandaloneSetup is given the path
        to the platform. This is the path to which platform resource URIs are
        resolved relative to. It usually points to the workspace or check out
        location of the plugin project, which is usually one directory above
        the working directory in which a workflow is executed.
Metamodel instances are often shared between different
        components that make use of expressions (most notably the Xpand
        Generator,
        XtendComponent and
        CheckComponent). Normally you don't want that a
        Metamodel instance configured and instantiated for each workflow
        component. MWE lets you instantiate a class using the
        <bean> tag and by giving the bean an id
        value, this same instance can be referred to using the idRef
        attribute. This would lead to this workflow:
<bean class="org.eclipse.emf.mwe.utils.StandaloneSetup"> <platformUri value=".."/> <registerGeneratedEPackage value="my.generated.MetaModel1Package"/> <registerEcoreFile value="platform:/resource/my/java/package/metamodel2.ecore"/> </bean> <bean id="mm_emf" class="org.eclipse.type.emf.EmfRegistryMetaModel"/> ... <component class="org.eclipse.xpand2.Generator"> <metaModel idRef="mm_emf"/> ... </component>
With Xpand you can work on different kinds of Model representations at the same time in a transparent manner. One can work with EMF models, XML DOM models, and simple JavaBeans in the same Xpand template. You just need to configure the respective MetaModel implementations.
If you want to do so you need to know how the type lookup works. Let us assume that we have an EMF metamodel and a model based on some Java classes. Then the following would be a possible configuration:
<component class="org.eclipse.xpand2.Generator">
   <metaModel class="org.eclipse.internal.xtend.type.impl.java.JavaMetaModel"/>
   <metaModel class="org.eclipse.xtend.typesystem.emf.EmfRegistryMetaModel">
      <metaModelFile value="my/java/package/metamodel.ecore"/>
   </metaModel>
   ...
</component>
When the runtime needs to access a property of a given object, it
      asks the metamodels in the configured order. Let us assume that our
      model element is an instance of the Java type
      org.eclipse.emf.ecore.EObject and it is a dynamic
      instance of an EMF EClass MyType.
We have three Metamodels:
The first one will return the type Object
      (not java.lang.Object but
      Object of 
Xpand
!). At this
      point the type Object best fits the request, so
      it will act as the desired type.
The second metamodel returns a type called
      org::eclipse::emf::ecore::EObject The type system
      will check if the returned type is a specialization of the current
      'best-fit' type (Object). It is, because it
      extends Object (Every metatype has to extend
      Object). At this time the type system assumes
      org::eclipse::emf::ecore::EObject to be the
      desired type.
The third metamodel will return
      metamodel::MyType which is the desired type. But
      unfortunately it doesn't extend
      org::eclipse::emf::ecore::EObject as it has
      nothing to do with those Java types. Instead it extends
      emf::EObject which extends
      Object.
We need to swap the configuration of the two metamodels to get the desired type.
<component class="org.eclipse.xpand2.Generator">
   <metaModel class="org.eclipse.xtend.typesystem.emf.EmfMetaModel">
      <metaModelFile value="my/java/package/metamodel.ecore"/>
   </metaModel>
   <metaModel class="org.eclipse.internal.xtend.type.impl.java.JavaMetaModel"/>
   ...
</component>
The order of the metamodels is important for the work within the Xpand-editors. The metamodels to work with can be configured inside the Xtend/Xpand -properties dialog. The Activated metamodel contributors table is a ordered list. The more specific metamodels have to be placed at the top of the list.
 
In the following, each of the built-in metamodels that come with Xpand will be documented. Furthermore, there will be some guidelines on how to implement your own metamodel.
This section will describe the metamodels that can be used for
        EMF models. 
Please note that you have to
        execute one of the setup utility classes, Setup
        or StandaloneSetup, in your workflow before you
        can use one of the EMF metamodels.
This metamodel looks for the referenced metamodels in the global EMF model registry. This means, when using this metamodel, only models that are registered in this global EMF model registry will be accessible from within the metamodel.
This metamodel provides the following configuration property:
Table 1. Properties of
            EmfRegistryMetaModel
| Name of property | Description | 
|---|---|
| useSingleGlobalResourceSet | This boolean property determines the way resource sets are used. If set to true , all model resources will be stored in a single global resource set. Otherwise, a separate resource set will be used for each model resource. | 
This metamodel is a specialized version of the EMF registry metamodel. In addition to the features of the former, it allows to specify an unregistered model in different ways that will be added to the metamodel.
This metamodel provides the following configuration properties:
Table 2. Properties of EmfMetaModel
| Name of property | Description | 
|---|---|
| useSingleGlobalResourceSet | This boolean property determines the way resource sets are used. If set to true , all model resources will be stored in a single global resource set. Otherwise, a separate resource set will be used for each model resource. | 
| metaModelFile | Sets the path to the Ecore file that will be added to the metamodel. | 
| metaModelDescriptor | Adds a model to the metamodel by specifying the name of an EPackage descriptor class. | 
| metaModelPackage | Adds a model to the metamodel by specifying the name of an EPackage. | 
Xpand
 also provides several metamodels that
        allow to use UML models in conjunction with this model-to-text
        generation framework. 
Please note that you
        have to execute the setup utility class Setup
        in your workflow before you can use one of the UML
        metamodels
This metamodel is a specialized version of the EMF metamodel . It provides access to UML2 models, and it has the following configuration properties:
Table 3. Properties of UML2MetaModel
| Name of property | Description | 
|---|---|
| useSingleGlobalResourceSet | This boolean property determines the way resource sets are used. If set to true , all model resources will be stored in a single global resource set. Otherwise, a separate resource set will be used for each model resource. | 
| modelFile | Sets the path to the UML2 model file that will be added to the metamodel. | 
This implementation will be rarely used, since usually profiled UML models will be used and therefore the Profile Metamodel is.
This metamodel allows to apply UML profiles to UML2 models, and extends the UML2 Metamodel. It has the following configuration properties:
Table 4. Properties of
            ProfileMetaModel
| Name of property | Description | 
|---|---|
| useSingleGlobalResourceSet | This boolean property determines the way resource sets are used. If set to true , all model resources will be stored in a single global resource set. Otherwise, a separate resource set will be used for each model resource. | 
| modelFile | Sets the path to the UML2 model file that will be added to the metamodel. Use resource URIs for the values. | 
| profile | Sets the path to the UML profile that will be applied to the UML2 model. This property can be used multiple times if more than one profile is used. Use resource URIs for the values. | 
The XMI reader component is important when working with UML models. It allows to read out a model stored in an XMI file and put its contents into a model slot.
The XMIReader component provides the
          following configurable properties:
Table 5. Properties of XMIReader
| Name of property | Description | 
|---|---|
| metaModelFile | Sets the path to the Ecore file that will be added to the metamodel. | 
| metaModelDescriptor | Adds a model to the metamodel by specifying the name of an EPackage descriptor class. | 
| metaModelPackage | Adds a model to the metamodel by specifying the name of an EPackage. | 
| outputSlot | Sets the name of the model slot where the read model will be stored in. | 
| firstElementOnly | This boolean property determines if only the first model element of the XMI file will be used. If set to true , only the first model element will be used, all other elements will be ignored. Otherwise, all model elements in the XMI file will be used. | 
The Java metamodel allows normal Java classes as metatypes for
        your metamodel. The JavaMetaClass uses the
        strategy pattern to define how the elements are exactly mapped to the
        metamodel elements. There is a class called
        org.eclipse.internal.xtend.type.impl.java.JavaBeansMetaModel
        that is preconfigured with a strategy that maps simple Java beans onto
        the metamodel elements.
The Java metamodel has no configurable properties.
The XSD metamodel provides access to models implemented in the XML Schema Definition language. It has the following configuration properties:
Table 6. Properties of XSDMetaModel
| Name of property | Description | 
|---|---|
| id | Sets the ID of the current model. | 
| registerPackagesGlobally | This boolean property determines if the model packages will be registered globally. If set to true , the model packages will be registered in the global registry. Otherwise, packages will not be registered. | 
| savePackagesPath | Sets the path where model packages will be saved (in XMI format). | 
The Xpand framework also allows you to integrate new metamodel implementations. This section quickly outlines the steps that have to be taken in order to implement a metamodel:
Create a class that implements the
            MetaModel interface.
In order to be able to integrate your metamodel into the
            Eclipse UI, you also have to provide a metamodel contributor class
            for your metamodel implementation that implements either the
            MetaModelContributor or the
            MetaModelContributor2 interface.
Finally, you have to extend the
            org.eclipse.xtend.shared.ui.metaModelContributors
            extension point in order to register your metamodel contributor
            with the Eclipse UI.