Generating code from the example model

Generating code from the example model

To run the Xpand generator, you have to define a workflow. It controls which steps (loading models, checking them, generating code) the generator executes. For details on how workflow files work, please take a look at the Modeling Workflow Engine Reference Documentation .

Create a workflow.mwe and a workflow.properties in the src folder. The contents of these files is shown below:

<workflow>
  <property file="workflow.properties"/>

  <bean class="org.eclipse.emf.mwe.utils.StandaloneSetup" >
    <platformUri value=".."/>
    <registerGeneratedEPackage value="data.DataPackage"/>
  </bean>

  <component class="org.eclipse.emf.mwe.utils.Reader">
    <uri value="platform:/resource/${modelFile}" />
    <modelSlot value="model" />
  </component>
</workflow>

workflow.properties:

modelFile=platform:/resource/xpand.demo.emf.datamodel/src/example.data
srcGenPath=src-gen
fileEncoding=ISO-8859-1

The workflow tries to load stuff from the classpath; so, for example, the data.DataPackage class is resolved from the classpath, as is the model file specified in the properties (modelFile=example.data)

This instantiates the example model and stores in a workflow slot named model. Note that in the metamodelPackage slot, you have to specify the EMF package object (here: data.DataPackage), not the Java package (which would be data here).

Before you actually run the workflow, make sure your metamodel can be found on the classpath. In our case, this can be achieved by adding the xpand.demo.emf.datamodel project to the plug-in dependencies of xpand.demo.emf.datamodel.generator. To do this, double click the file xpand.demo.emf.datamodel.generator/META-INF/MANIFEST.MF. The manifest editor will appear. Go to the Dependencies tab and click on Add... to add a few new dependencies.

  • xpand.demo.emf.datamodel

  • org.eclipse.emf.mwe.utils

  • org.eclipse.emf.ecore.xmi

  • org.eclipse.jface.text

  • org.antlr.runtime

  • com.ibm.icu

  • org.eclipse.jdt.core


Do not forget to save the manifest file!

Now, you can run the workflow from within Eclipse:


The following should be the output:

INFO: --------------------------------------------------------------------------------------
INFO: EMF Modeling Workflow Engine 0.7.2, Build v200908120417
INFO: (c) 2005-2009 openarchitectureware.org and contributors
INFO: --------------------------------------------------------------------------------------
INFO: running workflow: ../xpand.demo.emf.datamodel.generator/src/workflow.mwe
INFO: 
14.04.2010 15:49:18 org.eclipse.emf.mwe.utils.StandaloneSetup setPlatformUri
INFO: Registering platform uri '..'
14.04.2010 15:49:18 org.eclipse.emf.mwe.utils.StandaloneSetup addRegisterGeneratedEPackage
INFO: Adding generated EPackage 'data.DataPackage'
14.04.2010 15:49:18 org.eclipse.emf.mwe.core.container.CompositeComponent internalInvoke
INFO: Reader: Loading model from platform:/resource/xpand.demo.emf.datamodel.generator/src/example.data
14.04.2010 15:49:19 org.eclipse.emf.mwe.core.WorkflowRunner executeWorkflow
INFO: workflow completed in 116ms!

No code is generated yet. This is not surprising, since we did not yet add any templates. Let us change this. Create a package templates in the srcfolder and within the package a file called Root.xpt.

The Root.xpt looks as follows. By the way, if you need to type the guillemets (« and »), the editor provides keyboard shortcuts with Ctrl + < and Ctrl + > .

«DEFINE Root FOR data::DataModel»
  «EXPAND Entity FOREACH entity»
«ENDDEFINE»

«DEFINE Entity FOR data::Entity»
  «FILE name + ".java"»
    public class «name» {
      «FOREACH attribute AS a»
        // bad practice
        private «a.type» «a.name»;
      «ENDFOREACH»
    }
  «ENDFILE»
«ENDDEFINE» 

We have to extend the workflow.mwe file, in order to use the template just written:

<workflow>
  <property file="workflow.properties"/>

  ..

  <component class="org.eclipse.emf.mwe.utils.Reader">
    <uri value="platform:/resource/${modelFile}" />
    ..
</workflow>

First, we clean up the directory where we want to put the generated code.

<component class="org.eclipse.emf.mwe.utils.DirectoryCleaner">
  <directory value="${srcGenPath}" />
</component>

Then, we start the generator component. Its configuration is slightly involved.

<component class="org.eclipse.xpand2.Generator">

First of all, you have to define the metamodel. In our case, we use the EmfMetaModel since we want to work with EMF models. Also, you have to specific the class name of the EMF package that represents that metamodel. It has to be on the classpath.

  <metaModel id="mm"
   class="org.eclipse.xtend.typesystem.emf.EmfRegistryMetaModel">
  </metaModel>

Then, you have to define the entry statement for Xpand . Knowing that the model slot contains an instance of data.DataModel (the XmiReader had put the first element of the model into that slot, and we know from the data that it is a DataModel), we can write the following statement. Again, notice that model refers to a slot name here!

   <expand value="templates::Root::Root FOR model"/>

We then specify where the generator should put the generated code and that this generated code should be processed by a code beautifier:

   <outlet path="${srcGenPath}/">
      <postprocessor
        class="org.eclipse.xpand2.output.JavaBeautifier"/>
    </outlet>

Now, we are almost done.

 </component>
</workflow>

You also need to add the srcGenPath to the workflow.properties file.

modelFile=example.data
srcGenPath=src-gen

So, if you restart the generator now, you should get a file generated that looks like this:

public class Person {
  // bad practice
  public String lastName;
}