blob: 7b3f04d60cab8c96a5684d0867f1953386efdb4a [file] [log] [blame]
<html>
<head>
<title>Extensions</title>
<link href="book.css" rel="stylesheet" type="text/css"/>
<meta content="DocBook XSL Stylesheets V1.75.1" name="generator"/>
<link rel="home" href="index.html" title="Xpand Documentation"/>
<link rel="up" href="emf_tutorial.html" title="Getting Started"/>
<link rel="prev" href="emf_tutorial_checking_contraints_with_check.html" title="Checking Constraints with the Check Language"/>
<link rel="next" href="Reference.html" title="Part I. Reference"/>
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<h1 xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0">Extensions</h1>
<div class="section" title="Extensions">
<div class="titlepage">
<div>
<div>
<h2 class="title" style="clear: both">
<a name="emf_tutorial_extensions"/>Extensions</h2>
</div>
</div>
</div>
<p>It is often the case that you need additional properties in the
templates; these properties should not be added to the metaclasses
directly, since they are often specific to the specific code generation
target and thus should not "pollute" the metamodel.</p>
<p>It is possible to define such extensions<a name="N104BB" class="indexterm"/> external to the metaclasses. For details see the
<span class="emphasis">
<em>Xtend Language Documentation</em>
</span>, we provide an simple
example here.</p>
<div class="section" title="Expression Extensions">
<div class="titlepage">
<div>
<div>
<h3 class="title">
<a name="emf_tutorial_expression_extensions"/>Expression Extensions</h3>
</div>
</div>
</div>
<p>Assume we wanted to change the <span class="emphasis">
<em>Attribute</em>
</span>s
part of the template as follows:</p>
<pre class="programlisting">«FOREACH attribute AS a»
private «a.type» «a.name»;
public void «a.setterName()»( «a.type» value ) {
this.«a.name» = value;
}
public «a.type» «a.getterName()»() {
return this.«a.name»;
}
«ENDFOREACH»</pre>
<p>To make this work, we need to define the
<code class="methodname">setterName()</code> and
<code class="methodname">getterName()</code> operations. We do this by writing
a so-called extension file; we call it <code class="filename">java.ext</code>. It
must have the <code class="filename">.ext</code> suffix to be recognized by
Xpand; the <span class="emphasis">
<em>Java</em>
</span> name is because it contains
Java-generation specific properties. We put this file directly into the
<code class="filename">templates</code> directory under
<code class="filename">src</code>, i.e. directly next to the
<code class="filename">Root.xpt</code> file. The extension file looks as
follows:</p>
<p>First, we have to import the data metamodel; otherwise we would
not be able to use the <span class="emphasis">
<em>Attribute</em>
</span> metaclass.</p>
<pre class="programlisting">import data;</pre>
<p>We can then define the two new operations
<code class="methodname">setterName</code> and
<code class="methodname">getterName</code>. Note that they take the type on
which they are called as their first parameter, a kind of "explicitly
this". After the colon we use an expression that returns the
to-be-defined value.</p>
<pre class="programlisting">String setterName(Attribute ele) :
'set'+ele.name.toFirstUpper();
String getterName(Attribute ele) :
'get'+ele.name.toFirstUpper();</pre>
<p>To make these extensions work, we have to add the following line
to the beginning of the <code class="filename">Root.xpt</code> template
file:</p>
<pre class="programlisting">«EXTENSION templates::java»</pre>
</div>
<div class="section" title="Java Extensions">
<div class="titlepage">
<div>
<div>
<h3 class="title">
<a name="emf_tutorial_java_extensions"/>Java Extensions<a name="N10509" class="indexterm"/>
</h3>
</div>
</div>
</div>
<p>In case you cannot express the "business logic" for the expression
with the expression language, you can fall back to Java. Take a look at
the following extension definition file. It is called
<code class="filename">util.ext</code> and is located in <code class="filename">src/datamodel/generator/util</code>:</p>
<pre class="programlisting">String timestamp() :
JAVA datamodel.generator.util.TemplateUtils.timestamp();</pre>
<p>Here, we define an extension that is independent of a specific
model element, since it does not have a formal parameter! The
implementation of the extension is delegated to a static operation of a
Java class. Here is its implementation:</p>
<pre class="programlisting">public class TemplateUtils {
public static String timestamp() {
return String.valueOf( System.currentTimeMillis() );
}
}</pre>
<p>This element can be used independent of any model element – it is
available globally.</p>
<p>Sometimes, it is necessary to access extensions not just from
templates and other Xtend files but also from Java code. The following
example is of this kind: We want to define properties that derive the
name of the implementation class from the entity name itself. The best
practice for this use case is to implement the derived property as a
Java method, as above. The following piece of code declares properties
for <code class="classname">Entity</code>:</p>
<pre class="programlisting">package datamodel;
import data.Entity;
public class EntityHelper {
public static String className( Entity e ) {
return e.getName()+"Implementation";
}
public static String classFileName( Entity e ) {
return className(e)+".java";
}
}</pre>
<p>In addition, to access the properties from the template files, we
define an extension that uses the helper methods. The
<code class="filename">helper.ext</code> file is located right next to the helper
class shown above, i.e. in the <span class="package">datamodel</span>
package:</p>
<pre class="programlisting">import data;
String className( Entity e ) :
JAVA datamodel.EntityHelper.className(data.Entity);
String classFileName( Entity e ) :
JAVA datamodel.EntityHelper.classFileName(data.Entity);</pre>
<p>In addition to these new properties being accessible from Java
code by invoking <code class="code">EntityHelper.className(someEntity)</code>, we can
now write the following template:</p>
<pre class="programlisting">«EXTENSION templates::java»
«EXTENSION datamodel::generator::util::util»
«EXTENSION datamodel::helper»
«DEFINE Root FOR data::DataModel»
«EXPAND Entity FOREACH entity»
«ENDDEFINE»
«DEFINE Entity FOR data::Entity»
«FILE classFileName()»
// generated at «timestamp()»
public abstract class «className()» {
«FOREACH attribute AS a»
private «a.type» «a.name»;
public void «a.setterName()»( «a.type» value ) {
this.«a.name» = value;
}
public «a.type» «a.getterName()»() {
return this.«a.name»;
}
«ENDFOREACH»
}
«ENDFILE»
«ENDDEFINE»</pre>
<p>For completeness, the following illustration shows the resulting
directory and file structure. </p>
<div class="figure">
<a name="emf_tutorial_what_happened_so_far"/>
<p class="title">
<b>Figure 17. What has happened so far</b>
</p>
<div class="figure-contents">
<div class="mediaobject">
<img src="images/emf_tutorial/generator_structure_so_far.png" alt="What has happened so far"/>
</div>
</div>
</div>
<p>
<br class="figure-break"/>
</p>
</div>
</div>
</body>
</html>