| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
| <title>JET Tutorial Part 2 (Write Code that Writes Code)</title> |
| <link rel="stylesheet" href="../default_style.css"> |
| </head> |
| |
| <body lang="EN-US" xml:lang="EN-US"> |
| |
| <div align="right"> <font face="Times New Roman, Times, serif" size="2">© |
| Copyright <a href="http://www.azzurri.jp">Azzurri Ltd.</a> 2003, 2004. All rights |
| reserved</font> |
| <table border=0 cellspacing=0 cellpadding=2 width="100%"> |
| |
| <tr> |
| <td align=LEFT valign=TOP colspan="2" bgcolor="#0080C0"><b><font face="Arial,Helvetica"><font color="#FFFFFF"> Eclipse |
| Corner Article</font></font></b></td> |
| </tr> |
| </table> |
| </div> |
| <div align="left"> |
| <h1><img src="images/Idea.jpg" align=CENTER width="120" height="86" /></h1> |
| </div> |
| |
| <h1 align="center">JET Tutorial Part 2 (Write Code that Writes Code)</h1> |
| |
| <blockquote> |
| <b>Summary</b> |
| |
| <br/> |
| <p>In Part 2 of this JET (Java Emitter Templates) tutorial, we will take a look |
| at the JET engine API. You will learn how to write plug-ins that use the classes |
| in the JET package to generate Java source code.</p> |
| <p>As a real-world example, we will create a plug-in that takes user input and |
| generates a Typesafe Enumeration class. The generated source code is based |
| on a JET template that can be distributed with the plug-in, allowing users |
| of the plug-in to customize the generated code by editing the template.</p> |
| <p>This article also provides a short reference to the JET API.</p> |
| <p>Contributed by Remko Popma, Azzurri Ltd., remko.popma at azzurri dot jp, |
| August 26, 2003. Last update: May 31, 2004 for EMF 2.0 (Eclipse 3.0).</p> |
| |
| </blockquote> |
| |
| <hr width="100%"/> |
| |
| <h2>Source Code </h2> |
| <p>To run the example or view the source for code for this article you can unzip |
| <a href="org.eclipse.emf.examples.jet.article2_2.0.0.zip">org.eclipse.emf.examples.jet.article2_2.0.0.zip</a> |
| into your <i>plugins/</i> subdirectory. To use the example plug-in, you will |
| need <a href="http://www.eclipse.org/emf/" target="_blank">EMF</a> plug-in version |
| 2.0 installed.</p> |
| |
| <h2>Introduction </h2> |
| <center> |
| <table border="1" cellspacing="0" width="80%" cellpadding="3"> |
| <tbody> |
| <tr> |
| <td> |
| <p><b>Translation vs. Generation</b></p> |
| <p>An aspect of JET templates that is at first confusing is that generating |
| text takes two steps: translation and generation. The first step is |
| translating the template to a template implementation class. The second |
| step is using this template implementation class to generate the text. |
| </p> |
| <p>If your goal with JET is to generate Java source code, it can be confusing |
| that the template translation step also results in Java source code. Remember |
| that this source code is <i>not</i> the generated text. The source code |
| that is the result of the translation step is simply another form of the |
| template. </p> |
| |
| <p>If you have used JSP and servlets before, you can think of a JET template |
| as being equivalent to a JSP page. A JET template is translated to a |
| template implementation class, just like a JSP page is translated to |
| a servlet. The second step, where the template implementation class |
| generates text, is equivalent to the servlet creating and returning |
| HTML.</p> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| </center> |
| |
| <p><a href="../Article-JET/jet_tutorial1.html">Part 1</a> of this tutorial introduced |
| JET templates and explained how you can convert a project to a JET project to |
| have the JET Builder automatically translate templates in your project to template |
| implementation classes. </p> |
| <p>In part 2 of this tutorial, we will focus on writing a plug-in that uses the |
| classes in the JET package to generate Java source code. A plug-in that generates |
| text from a JET template can no longer rely on the JET Nature and JET Builder |
| to automatically translate templates. This is because JET Nature and JET Builder |
| operate only on workspace projects, not on plug-ins. Plug-ins need to use the |
| classes in the JET package to translate their templates. </p> |
| |
| <p>The next section will discuss some of the classes in the <tt class="code">org.eclipse.emf.codegen</tt> |
| package. We will see what the steps are to generate source code with JET, and |
| how the JET engine classes fit in. If you are anxious to see some code that |
| shows how to use these classes in practice, you can go straight to <a href="#example_plugin">A |
| Plug-in that Generates Source Code</a>. </p> |
| |
| <h2>Some JET Classes</h2> |
| <p>In this section, we will take a closer look at some of the classes in the JET |
| package. They can roughly be divided into two groups: </p> |
| <ul> |
| <li>Lower-level classes dealing with the nuts and bolts of translating a template |
| to a template implementation class. The <tt class="code">JETCompiler</tt> class brings |
| all these lower-level classes together to provide a single API for template |
| translation. </li> |
| |
| <li>Higher-level classes that build on top of <tt class="code">JETCompiler</tt> to accomplish |
| user tasks. In Part 1 of this tutorial, we have already seen <tt class="code">JETNature</tt> |
| and <tt class="code">JETBuilder</tt> at work. Other high-level classes are <tt class="code">CodeGen</tt> |
| and <tt class="code">JETEmitter</tt>. </li> |
| |
| </ul> |
| <p>The lower-level classes are not discussed in-depth in this article. For a description |
| of all classes in the <tt class="code">org.eclipse.emf.codegen</tt> plug-in, see the <a href="#jet_api_overview">JET |
| API Overview</a> section below. In the rest of this section, we will focus on |
| a few of the higher-level classes.</p> |
| <h4><tt class="code">org.eclipse.emf.codegen.jet.JETCompiler</tt></h4> |
| <p><tt class="code">JETCompiler</tt> is the core class for template translation. This class |
| is responsible for translating templates to the Java source code of a template |
| implementation class. The actual translation is delegated to other classes in |
| the same package. Clients create a JETCompiler object for a particular template |
| and then call the <tt class="code">parse</tt> method followed by the <tt class="code">generate</tt> |
| method to write the Java source code for the resulting template implementation |
| class to a specified stream.</p> |
| |
| <h4><tt class="code">org.eclipse.emf.codegen.jet.JETEmitter</tt></h4> |
| <p><tt class="code">JETEmitter</tt> provides a convenient high-level API for users of the |
| JET package. The <tt class="code">generate</tt> method of this class combines template |
| translation and text generation into a single step. By taking care of the gory |
| details of translating templates and compiling the Java source code of the translated |
| template implementation class, JETEmitter lets you focus on the final generator |
| output.</p> |
| <p>Another way of looking at JETEmitter is that it abstracts away the translation |
| step and lets you pretend that you can directly generate text with a template. |
| Following the <a href="http://www.joelonsoftware.com/articles/LeakyAbstractions.html" target="_blank">Law |
| of Leaky Abstractions</a>, we cannot always get away with this, and the <a href="#jetemitter_gotchas">JETEmitter |
| Gotchas</a> section below points to a few places where you have to be careful.</p> |
| <p>JETEmitter is the class we will be using in our plug-in, so we will go into |
| a little more detail here.</p> |
| |
| <p>A JETEmitter object is constructed with the uri of the template used to generate |
| text. Any type of uri is acceptable as long as a protocol handler is available. |
| This means that <tt class="code">file:/</tt> uris, <tt class="code">ftp:/</tt> uris and <tt class="code">http:/</tt><i> |
| </i>uris can all be used. Eclipse adds special protocol handlers for <tt class="code">platform:/base</tt>/, |
| <tt class="code">platform:/plugin/</tt>, <tt class="code">platform:/fragment/</tt> and <tt class="code">platform:/resource/</tt> |
| uris, so plug-ins can use a uri like <tt class="code">platform:/resource/myproject/myfolder/mytemplate.jet</tt> |
| to specify a template file. Note: Eclipse 3.0 has introduced <tt class="code">bundleentry</tt> to its list |
| of special protocols. It should be used in references to Eclipse elements such as plugins and features.</p> |
| |
| <p>In our example plug-in, we will distribute our template file together with our |
| plug-in, so the template file will be located in a <i>myplugin/templates/</i> |
| folder under the Eclipse <i>plugins/</i> folder. The following code can then |
| be used to locate and generate a template from this folder:</p> |
| <pre class="code"> String pluginId = "myplugin.id"; |
| String base = Platform.getBundle(pluginId).getEntry("/").toString(); |
| String uri = base + "templates/myTemplate.javajet"; |
| JETEmitter emitter = new JETEmitter(uri); |
| String generatedText = emitter.generate(new Object[] {parameter});</pre> |
| <p>After constructing a JETEmitter object, clients then call <tt class="code">generate</tt> |
| on it to generate text. The <tt class="code">generate</tt> method will perform the following |
| steps:</p> |
| |
| <ol> |
| <li>Create a project called <i>.JETEmitters</i> in the workspace </li> |
| <li>Prepare this project by giving it the Java Nature and adding classpath variables |
| to its classpath </li> |
| <li>Translate the template to a template implementation Java source file in |
| the <i>.JETEmitters</i> project </li> |
| <li>Build the project to compile the template implementation source code to |
| a Java <i>.class</i> file </li> |
| <li>Call the <tt class="code">generate</tt> method on the translated Java template implementation |
| class and return the generated text as a String</li> |
| </ol> |
| <p>* <i>.JETEmitters</i> is the default name for the project that is created during the template |
| translation. This value can be changed by the <tt class="code">setProjectName</tt> method.</p> |
| |
| |
| <p>Our example plug-in will use JETEmitter and save the generated text to a Java |
| source file in the workspace. The figure below shows the steps for generating |
| source code using JETEmitter. </p> |
| <p><img alt="Using JETEmitter to generate text from a plugin" src="images/jetemitter.gif"/> </p> |
| <h3><a name="jetemitter_gotchas"></a>JETEmitter Gotchas</h3> |
| <p>The JETEmitter class combines template translation and text generation into |
| a single step, which makes it a very convenient tool. However, it is important |
| that you know what takes place under the hood, otherwise you might be in for |
| some nasty surprises. This section highlights some "gotchas" that |
| I ran into, so that you don't make the same mistakes.</p> |
| |
| <h4>1. Plug-in Initialization Required </h4> |
| <p>It is not easy to use JET outside of Eclipse. JET is designed to run only as |
| a workspace application. Any application using JET must minimally run as an |
| Eclipse "headless" application so that plug-in initialization takes |
| place. (The term headless refers to running Eclipse without the user interface.)</p> |
| <p>This means that using JETEmitter from a simple standalone application (a standard |
| Java class with a <tt class="code">main</tt> method) <i>will not work</i>:</p> |
| <pre class="code"> // This fails: cannot use JETEmitter from a standalone application |
| public static void main(String[] args) { |
| JETEmitter emitter = new JETEmitter("/myproject/templates/HelloWorld.txtjet"); |
| |
| // this will throw a NullPointerException |
| String result = emitter.generate(new NullProgressMonitor(), {"hi" }); |
| |
| System.out.println(result); |
| </pre> |
| |
| <p>Note that this is not a restriction of just the JETEmitter class, many of the |
| classes in the <tt class="code">org.eclipse.emf.codegen</tt> plug-in have dependencies |
| on other plug-ins. The <a href="#appendix">Appendix</a> section below has more |
| details on using JET from standalone applications.</p> |
| <p>In the rest of this article we will assume that our code is running from inside |
| a plug-in.</p> |
| <h4>2. Classloader Issues </h4> |
| <p>You may get a NoClassDefFoundError when you pass a custom object as the argument |
| to the <tt class="code">JETEmitter.generate</tt> method. This can happen if the object |
| you pass as the argument is not one of the java "bootstrap" classes (the bootstrap |
| classes are the runtime classes in rt.jar and internationalization classes in |
| i18n.jar).</p> |
| |
| <p>To prevent this error you must specify the classloader of your plug-in when |
| using JETEmitter. If no classloader is specified, JETEmitter uses the classloader |
| of its own class, which is usually the classloader for the <tt class="code">org.eclipse.emf.codegen</tt> |
| plug-in, and this classloader can't see much. In recent versions of EMF (since |
| version 1.1.0 build 20030527_0913VL), JETEmitter has a constructor that takes |
| a classloader argument.</p> |
| <p>Note that another way to specify a classloader is to subclass JETEmitter in |
| your own project; if no classloader is specified, JETEmitter will use the classloader |
| of this subclass. (If you are using an older version of EMF, there are no constructors |
| that take a classloader argument and you will have no choice but to subclass |
| JETEmitter in your own project.)</p> |
| <p>The example below shows an action class that translates and invokes a selected |
| template using JETEmitter. The example shows how a JETEmitter can be constructed |
| <img src="images/tag_1.gif" width="24" height="13"/>with a classloader parameter or by <img src="images/tag_2.gif" width="24" height="13"/>constructing |
| an anonymous subclass.</p> |
| <pre class="code">package org.eclipse.emf.examples.jet.article2.actionexample; |
| // imports omitted |
| public class EmitAction implements IActionDelegate { |
| protected ISelection selection; |
| |
| public void selectionChanged(IAction action, ISelection selection) { |
| this.selection = selection; |
| action.setEnabled(true); |
| } |
| |
| public void run(IAction action) { |
| List files = (selection instanceof IStructuredSelection) |
| ? ((IStructuredSelection) selection).toList() |
| : Collections.EMPTY_LIST; |
| |
| for (Iterator i = files.iterator(); i.hasNext();) { |
| IFile file = (IFile) i.next(); |
| IPath fullPath = file.getFullPath(); |
| |
| String templateURI = "platform:/resource" + fullPath; |
| <b>Class</b><b>Loader classloader = getClass().getClassLoader();</b> |
| <img src="images/tag_1.gif" width="24" height="13"/> JETEmitter emitter = new JETEmitter(templateURI, <b>classloader</b>); |
| |
| // <b>or: use an anonymous subclass</b> |
| |
| <img src="images/tag_2.gif" width="24" height="13"/> // emitter = <b>new JETEmitter(templateURI) {}</b>; // notice the brackets |
| |
| try { |
| IProgressMonitor monitor = new NullProgressMonitor(); |
| String[] arguments = new String[] { "hi" }; |
| |
| String result = emitter.generate(monitor, arguments); |
| |
| saveGenerated(result, file); |
| |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| } |
| |
| // saveGenerated method omitted |
| } |
| </pre> |
| <h4>3. Classpath Issues </h4> |
| <p>JETEmitter translates your templates to Java source files in the <i>.JETEmitters</i> |
| project, and invokes the JavaBuilder to compile these source files. If your |
| templates use classes that are not standard Java classes, or not in the EMF |
| plug-in, you will need to add these classes to the classpath of the <i>.JETEmitters</i> |
| project, or the JavaBuilder cannot compile the template implementation source |
| files. Fortunately, JETEmitter provides a simple way to do this through the method |
| <tt class="code">addVariable</tt> which adds a <i>Classpath Variable</i> to the <i>.JETEmiter</i> project.</p> |
| <p>A <i>Classpath Variable</i> is a workspace-wide name that is used in Eclipse to refer to a jar file or |
| directory. The list of all such variables can be seen using the Window > Preferences > Java > |
| Classpath Variables menua action.. Your program will need to add a classpath variable for each |
| jar file or directory that is needed on the classpath of the <i>.JETEmiter</i> project.</p> |
| |
| |
| <h2><a name="example_plugin"></a>A Plug-in that Generates Source Code </h2> |
| <p>In this part of the JET Tutorial, we will write an Eclipse plug-in that uses |
| a JET template to generate Java source code for typesafe enumerations.</p> |
| <p>Our plug-in has to perform the following tasks:</p> |
| <ol> |
| <li>Collect user input values for the variables in our template: the class name, |
| the type and name of the attributes of the typesafe enumeration class, and |
| the values of these attributes for each instance. We will write a simple GUI |
| to collect these values.</li> |
| <li>Translate the JET template file to a Java template implementation class</li> |
| |
| <li>Invoke the template implementation class with an object that contains the |
| user input values collected by the GUI</li> |
| <li>Save the resulting generated source code to a location obtained from the |
| GUI</li> |
| </ol> |
| <p>In the following sections we will go through the steps above one by one.</p> |
| <h3><a name="typesafe_enum_example"></a>Typesafe Enumerations</h3> |
| <p>Let's have a look at a typesafe enumeration class to see what kind of source |
| code we want to generate. The Digit class below is an example typesafe enum.</p> |
| <pre class="code"> // an example typesafe enum |
| package x.y.z; |
| public class Digit { |
| <img src="images/tag_1.gif" width="24" height="13"/> public static final Digit ZERO = new Digit(0, "zero"); |
| public static final Digit ONE = new Digit(1, "one"); |
| public static final Digit TWO = new Digit(2, "two"); |
| public static final Digit THREE = new Digit(3, "three"); |
| // ... |
| public static final Digit NINE = new Digit(9, "nine"); |
| |
| private static final Digit[] ALL = |
| {ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE}; |
| |
| |
| <img src="images/tag_2.gif" width="24" height="13"/> private final int value; |
| private final String name; |
| |
| private Digit(int value, String name) { |
| this.value = value; |
| this.name = name; |
| } |
| |
| <img src="images/tag_3.gif" width="24" height="13"/> public static Digit lookup(int key) { |
| for (int i = 0; i < ALL.length; i++) { |
| if (key == ALL[i].getValue()) { return ALL[i]; } |
| } |
| // lookup failed: |
| // we have no default Digit, so we throw an exception |
| <img src="images/tag_4.gif" width="24" height="13"/> throw new IllegalArgumentException("No digit exists for " + key); |
| } |
| |
| public int getValue() { return value; } |
| public int getName() { return name; } |
| public String toString() { return getName(); } |
| }</pre> |
| <p>Let's take a closer look at this class. First of all, the Digit class has several |
| <b><img src="images/tag_1.gif" width="24" height="13"/>instances</b> - the constants |
| ZERO, ONE, TWO, etc. Each instance is defined by its Java variable name, "ZERO", |
| "ONE", "TWO"..., and the values for each <b><img src="images/tag_2.gif" width="24" height="13"/>attribute</b> |
| of the enumeration class. Most typesafe enums have one or more attributes. The |
| Digit class has two attributes: a <tt class="code">value</tt> integer and a <tt class="code">name</tt> |
| String.</p> |
| |
| <p>Our example Digit class also has a <b><img src="images/tag_3.gif" width="24" height="13"/><tt class="code">lookup</tt></b> |
| method, which returns the instance whose <tt class="code">value</tt> attribute equals |
| the specified int parameter. A lookup method introduces the concept of <b>key |
| attributes</b>. Many typesafe enums have one or more attributes that uniquely |
| distinguish one instance from another.</p> |
| <p><i>Note that key attributes are not required: the Java VM guarantees that every |
| newly constructed object is unique, so it is possible to have typesafe enumerations |
| that have no attributes at all, and simply distinguish their instances with |
| the <b>==</b> instance identity operator. This works fine, but often it is convenient |
| to have a key attribute that uniquely identifies an instance, and a <tt class="code">lookup</tt> |
| method that finds an instance for a specified key value.</i></p> |
| |
| <p>Our template does have a <tt class="code">lookup</tt> method, so we need to decide what |
| to do if <img src="images/tag_4.gif" width="24" height="13"/>no instance is found |
| for the specified key value. Basically there are three options: throwing an |
| Exception, returning a designated "default" instance, or returning |
| <tt class="code">null</tt>. Which option is best depends on the application in which |
| the class is used, so we should probably let the user decide.</p> |
| <p>Now that we've studied typesafe enums in more detail, let's summarize what |
| is customizable in a typesafe enumeration:</p> |
| <ul> |
| <li>package name </li> |
| <li>class name </li> |
| |
| <li>attributes, where each attribute </li> |
| <ul> |
| <li>has a type </li> |
| <li>has a name </li> |
| <li>may be a key attribute </li> |
| </ul> |
| <li>instances, where each instance </li> |
| |
| <ul> |
| <li>has a name </li> |
| <li>has a value for every attribute </li> |
| <li>may be the default instance to return for failed lookups</li> |
| </ul> |
| </ul> |
| <h3><a name="typesafe_enum_model"></a>A Simple Typesafe Enumeration Model </h3> |
| <p>A simple model for the customizable parts of a typesafe enum could look something |
| like this:</p> |
| <p></p> |
| |
| <table border="1" cellspacing="0"> |
| <tbody> |
| <tr> |
| <td><tt class="code">TypesafeEnum</tt></td> |
| </tr> |
| <tr> |
| <td><tt class="code">getInstances() : Instance[]<br/> |
| getAttributes() : Attribute[]<br/> |
| getKeyAttributes() : Attribute[]<br/> |
| |
| getDefaultInstance() : Instance<br/> |
| getPackageName() : String<br/> |
| getClassName() : String</tt></td> |
| </tr> |
| </tbody> |
| </table> |
| <p></p> |
| <table border="1" cellspacing="0"> |
| <tbody> |
| <tr> |
| <td><tt class="code">Instance</tt></td> |
| |
| </tr> |
| <tr> |
| <td><tt class="code"> getName() : String<br/> |
| getAttributeValues() : Properties<br/> |
| getAttributeValue(Attribute) : String<br/> |
| isDefault() : boolean</tt></td> |
| </tr> |
| |
| </tbody> |
| </table> |
| <p></p> |
| <table border="1" cellspacing="0"> |
| <tbody> |
| <tr> |
| <td><tt class="code">Attribute</tt></td> |
| </tr> |
| <tr> |
| <td><tt class="code"> getName() : String<br/> |
| |
| getType() : String<br/> |
| isKey() : boolean</tt></td> |
| </tr> |
| </tbody> |
| </table> |
| <p></p> |
| <p>In the next section we will use these classes to convert our Digit class to |
| a JET template for typesafe enumerations.</p> |
| <h3><a name="typesafe_enum_template"></a>A Typesafe Enumeration Template </h3> |
| <p>Now that we have a model, we can take our Digit class and replace all Digit-specific |
| code with JET scriptlets and expressions that call our model classes. The resulting |
| template could look something like this:</p> |
| |
| <pre class="code"> <span class="highlight"><span class="highlight"><%@ jet package="translated" imports="java.util.* article2.model.*" class="TypeSafeEnumeration" %></span></span> |
| <span class="highlight"><span class="highlight"><% TypesafeEnum enum = (TypesafeEnum) argument; %></span></span> |
| package <span class="highlight"><%=enum.getPackageName()%></span>; |
| |
| /** |
| * This final class implements a type-safe enumeration |
| * over the valid instances of a <span class="highlight"><%=enum.getClassName()%></span>. |
| * Instances of this class are immutable. |
| */ |
| public final class <span class="highlight"><%=enum.getClassName()%></span> { |
| |
| <span class="highlight"><% for (Iterator i = enum.instances(); i.hasNext(); ) { %></span> |
| |
| <span class="highlight"><% Instance instance = (Instance) i.next(); %></span> |
| |
| // <b>instance definition</b> |
| public static final <span class="highlight"><%=enum.getClassName()%></span> <span class="highlight"><%=instance.getName()%></span> = |
| <img src="images/tag_1.gif" width="24" height="13"/> new <span class="highlight"><%=enum.getClassName()%></span>(<span class="highlight"><%=instance.constructorValues()%></span>); |
| <span class="highlight"><% } %></span> |
| |
| |
| <span class="highlight"><% for (Iterator i = enum.attributes(); i.hasNext(); ) { %></span> |
| <span class="highlight"><% Attribute attribute = (Attribute) i.next(); %></span> |
| |
| // <b>attribute declaration</b> |
| <img src="images/tag_2.gif" width="24" height="13"/> private final <span class="highlight"><%=attribute.getType()%></span> m<span class="highlight"><%=attribute.getCappedName()%></span>; |
| <span class="highlight"><% } %></span> |
| |
| |
| /** |
| * Private <b>constructor</b>. |
| */ |
| <img src="images/tag_3.gif" width="24" height="13"/> private <span class="highlight"><%=enum.getClassName()%></span>(<span class="highlight"><%=enum.constructorParameterDescription()%></span>) { |
| <span class="highlight"><% for (Iterator i = enum.attributes(); i.hasNext(); ) { %></span> |
| <span class="highlight"><% Attribute attribute = (Attribute) i.next(); %></span> |
| <img src="images/tag_4.gif" width="24" height="13"/> m<span class="highlight"><%=attribute.getCappedName()%></span> = <span class="highlight"><%=attribute.getUncappedName()%></span>; |
| <span class="highlight"><% } %></span> |
| |
| } |
| |
| // <b>getter accessor methods</b> |
| <span class="highlight"><% for (Iterator i = enum.attributes(); i.hasNext(); ) { %></span> |
| <span class="highlight"><% Attribute attribute = (Attribute) i.next(); %></span> |
| /** |
| * Returns the <span class="highlight"><%=attribute.getName()%></span>. |
| * |
| * @return the <span class="highlight"><%=attribute.getName()%></span>. |
| */ |
| public <span class="highlight"><%=attribute.getType()%></span> get<span class="highlight"><%=attribute.getCappedName()%></span>() { |
| return m<span class="highlight"><%=attribute.getCappedName()%></span>; |
| } |
| |
| <span class="highlight"><% } %></span> |
| |
| // lookup method omitted... |
| }</pre> |
| |
| <p>As you can see, the template calls some methods that were not in the simple |
| model we introduced earlier. We have added a few convenience methods, like the |
| <tt class="code"><img src="images/tag_2.gif" width="24" height="13"/>Attribute.getCappedName()</tt> |
| and <tt class="code"><img src="images/tag_4.gif" width="24" height="13"/>getUncappedName()</tt> |
| methods. Such methods help to keep the template simple.</p> |
| <p>Another example of methods we added to the model are the <tt class="code"><img src="images/tag_3.gif" width="24" height="13"/>TypesafeEnum.constructorParameterDescription()</tt> |
| method and the <tt class="code"><img src="images/tag_1.gif" width="24" height="13"/>Instance.constructorValues()</tt> |
| method. The implementation of the <tt class="code">constructorValues</tt> method is shown |
| below. </p> |
| |
| <pre class="code">// class Instance |
| /** |
| * Convenience method that returns the attribute values of this instance, |
| * in the order expected by the constructor of this instance. |
| * |
| * @return a comma-separated list of all attribute values of this instance, |
| * formatted like <tt class="code">attrib1-value, attrib2-value (, ...)</tt> |
| */ |
| public String constructorValues() { |
| StringBuffer result = new StringBuffer(); |
| for (Iterator i = getType().attributes(); i.hasNext(); ) { |
| Attribute attribute = (Attribute) i.next(); |
| result.append(getAttributeValue(attribute)); |
| if (i.hasNext()) { |
| result.append(", "); |
| } |
| } |
| return result.toString(); |
| } |
| </pre> |
| <p>The <tt class="code">constructorValues</tt> method loops through the attributes of the |
| typesafe enum, looks up the value for each attribute in the instance, and concatenates |
| these values into a string, separated by commas. For example, in our <tt>Digit</tt> |
| typesafe enum class above, this method would return <tt>"0, \"zero\""</tt> |
| for the "ZERO" instance. </p> |
| |
| <p>We could have looped through the attribute values in the template, but that |
| would have made the template much more difficult to read. Pushing this logic |
| into the model made the template more readable and easier to maintain. On the |
| other hand, we lost some flexibility because users cannot customize that logic |
| anymore by editing the template. This is a trade-off you have to make. Which |
| is better depends on your template and your application.</p> |
| <h3><a name="gui"></a>A GUI to Collect User Input </h3> |
| <p>Now that we have a model and a template, we still need two more pieces to finish |
| our plug-in: we need a GUI to collect values from the user to populate our model |
| with, and we need to invoke our template with the populated model to generate |
| source code and save this source code to a location in the workspace.</p> |
| <p>Let's start with the GUI. The workbench provides a few wizards that do something |
| similar to what we have in mind, for example the New Class, New Interface and |
| New JUnit TestCase wizards. It probably makes sense to have our GUI look similar |
| to these wizards and make it accessible from the standard menu and toolbar locations.</p> |
| <p>Our wizard has three pages. The first page, shown below, looks like a simplified |
| version of the New Class wizard. In fact, we are using the same framework that |
| the New Class wizard uses, the <tt class="code">org.eclipse.jdt.ui.wizards</tt> package. |
| In the first page, we collect the package name and the class name of the typesafe |
| enum, and the location where the result should be saved.</p> |
| <p><img alt="GUI wizard page one: class, package and location of the typesafe enum" src="images/enum_gui_page1.gif"/> |
| </p> |
| <p></p> |
| <p>Our second page collects information on the attributes of the typesafe enum |
| class. Every attribute has a name and a type, and may be one of the key attributes. |
| Our second wizard page is shown below:</p> |
| |
| <p><img alt="GUI wizard page two: attributes of the typesafe enum" src="images/enum_gui_page2.gif"/></p> |
| <p></p> |
| <p>Our third and last wizard page, shown below, collects information on the instances |
| of the typesafe enum. The user inputs the instance name, and for each instance |
| provides values for all attributes.</p> |
| <p>Finally, one of the instances may be the "default" instance, which |
| is the instance returned by the <tt class="code">lookup</tt> method if no instance was |
| found for the specified key attribute values.</p> |
| <p><img alt="GUI wizard page three: instances of the typesafe enum" src="images/enum_gui_page3.gif"/></p> |
| <h3><a name="invoke_plugin_template"></a>Invoking the Template </h3> |
| <p>Now that we have a GUI to populate our model, we can finally use what we learned |
| in the first part of this article, and generate source code with our template.</p> |
| |
| <p>When a user presses Finish on the wizard, the <tt class="code">performFinish</tt> method |
| in our wizard is called. The code below shows how we <img src="images/tag_1.gif" width="24" height="13"/>use |
| a custom subclass of JETEmitter to <img src="images/tag_2.gif" width="24" height="13"/>add |
| the jar file of our plug-in to the classpath of the <i>.JETEmitters</i> project |
| before we <img src="images/tag_3.gif" width="24" height="13"/>call generate on |
| the JETEmitter. The generated typesafe enum source code is <img src="images/tag_4.gif" width="24" height="13"/>saved |
| to the location in the workspace that the user specified.</p> |
| <pre class="code"> // class NewTypesafeEnumCreationWizard |
| protected void finishPage(IProgressMonitor monitor) |
| throws InterruptedException, CoreException { |
| |
| String pluginId = "org.eclipse.emf.examples.jet.article2"; |
| String base = Platform.getBundle(pluginId).getEntry("/").toString(); |
| String relativeUri = "templates/TypeSafeEnumeration.javajet"; |
| <img src="images/tag_1.gif" width="24" height="13"/> JETEmitter emitter = new JETEmitter(base + relativeUri, getClass().getClassLoader()); |
| <img src="images/tag_2.gif" width="24" height="13"/> emitter.addClasspathVariable("JET_TUTORIAL", pluginId); |
| |
| TypesafeEnum model = mPage1.getTypesafeEnumModel(); |
| IProgressMonitor sub = new SubProgressMonitor(monitor, 1); |
| |
| <img src="images/tag_3.gif" width="24" height="13"/> String result = emitter.generate(sub, new Object[] { model }); |
| monitor.worked(1); |
| |
| <img src="images/tag_4.gif" width="24" height="13"/> IFile file = save(monitor, result.getBytes()); |
| |
| selectAndReveal(file); |
| openResource(file); |
| }</pre> |
| <h3><a name="pluginxml"></a>Registering our Wizard </h3> |
| <p>Our final code snippet below shows the part of our <tt class="code">plugin.xml</tt> configuration |
| file where we register our wizard as a contribution to the workbench.</p> |
| <pre class="code"> <extension point="org.eclipse.ui.newWizards"> |
| <wizard |
| name="Typesafe Enum" |
| icon="icons/newenum_wiz.gif" |
| category="org.eclipse.jdt.ui.java" |
| id="org.eclipse.emf.examples.jet.article2.ui.NewTypesafeEnumCreationWizard"> |
| <description> |
| Create a Typesafe Enumeration |
| </description> |
| <class class="org.eclipse.emf.examples.jet.article2.ui.NewTypesafeEnumCreationWizard"> |
| <img src="images/tag_1.gif" width="24" height="13"/> <parameter name="javatype" value="true"/> |
| </class> |
| </wizard> |
| </extension> |
| </pre> |
| <p>Now our wizard is activated when users select File > New > Other > |
| Java > Typesafe Enum from the workbench, as shown in the image below. </p> |
| <p><img alt="Typesafe Enum wizard shows up in the New creation wizard" src="images/new_creation_wizard.gif"/> |
| </p> |
| <p>Note that we set the <tt class="code"><img src="images/tag_1.gif" width="24" height="13"/>javatype</tt> |
| attribute to true in the wizard extension element in the <tt class="code">plugin.xml</tt> |
| file. This will cause our wizard to show up as an action on the toolbar in the |
| Java Perspective, as shown in the image below.</p> |
| |
| <p><img alt="Typesafe Enum wizard shows up as an action on the toolbar in the Java Perspective" src="images/new_toolbar.gif"/> |
| </p> |
| <p></p> |
| <h2><a name="conclusion"></a>Conclusion </h2> |
| JET can be a great help for applications that need to generate text. Templates |
| are as much of an improvement to code generation as JSP pages were to old style |
| servlets. |
| <p>When using JET, you need to decide whether you want to distribute your templates |
| with your application, or distribute only the template implementation classes.</p> |
| <p>If your goal is to simplify the text generation capabilities of your application, |
| then using JET Nature and JET Builder to automatically translate your templates |
| is a good choice. See <a href="../Article-JET/jet_tutorial1.html">JET Tutorial |
| Part 1</a> for details. In that case you only need to distribute the translated |
| template implementation classes with your application, not the templates themselves.</p> |
| <p>On the other hand, if it is important for your application that users have |
| ultimate control over the generated text, you may want to distribute the template |
| files themselves with your application. In that case, you will need to translate |
| these templates every time you generate text. The plug-in we wrote in this article |
| is an example of this type of application.</p> |
| <p>This article explained what classes are available in the JET package to achieve |
| this and showed how to use these classes with an Eclipse plug-in. The appendix |
| below provides an overview of the JET API and shows how it can be used in headless |
| or standalone applications.</p> |
| |
| <h2><a name="appendix"></a>Appendix</h2> |
| <h3><a name="jet_api_overview"></a>JET API Overview </h3> |
| <b>Package org.eclipse.emf.codegen</b> |
| <p></p> |
| <table border="1" cellspacing="0"> |
| <tbody> |
| <tr> |
| <td><b>Class</b></td> |
| <td><b>Description</b></td> |
| </tr> |
| |
| <tr> |
| <td valign="top"><tt class="code">CodeGen</tt></td> |
| <td> |
| <p>The <tt class="code">CodeGen</tt> class can translate a JET template to Java source |
| code and optionally merge the template implementation Java source code |
| with an existing Java class. <tt class="code">CodeGen</tt> can be used as an Eclipse |
| headless application. The <tt class="code">run</tt> method expects a String array parameter |
| of two or three elements: </p> |
| |
| <ul> |
| <li> the uri of the template to translate </li> |
| <li>the target path where the translation result should be saved </li> |
| <li>an optional <tt class="code">JMerge</tt> control model file specifying how to merge |
| the new translation result with the source code of an existing Java |
| class</li> |
| </ul> |
| |
| </td> |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">CodeGenPlugin</tt></td> |
| <td>The plug-in class for the JET package.</td> |
| </tr> |
| </tbody> |
| </table> |
| <p></p> |
| |
| <b>Package org.eclipse.emf.codegen.jet</b> |
| <p></p> |
| <table border="1" cellspacing="0"> |
| <tbody> |
| <tr> |
| <td><b>Class</b></td> |
| <td><b>Description</b></td> |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">IJETNature</tt></td> |
| |
| <td>Interface extending <tt class="code">org.eclipse.core.resources.IProjectNature</tt>. |
| Defines some of the properties that a JET nature has. Implemented by <tt class="code">JETNature</tt>. |
| Used as a filter for project property pages by the <tt class="code">org.eclipse.emf.codegen.ui</tt> |
| plugin.</td> |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETAddNatureOperation</tt></td> |
| <td>A <tt class="code">org.eclipse.core.resources.IWorkspaceRunnable</tt> for adding the |
| JET nature to a project in the workspace. Used by the <tt class="code">AddJETNatureAction</tt> |
| in the <tt class="code">org.eclipse.emf.codegen.ui</tt> plug-in.</td> |
| |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETBuilder</tt></td> |
| <td>This class extends <tt class="code">org.eclipse.core.resources.IncrementalProjectBuilder</tt>. |
| When its <tt class="code">build</tt> method is invoked, it delegates to <tt class="code">JETCompileTemplateOperation</tt> |
| to translate all templates in the workspace project that have been changed |
| since the previous build. Templates must be located in one of the folders |
| specified as Template Containers in the JET Nature of the project.</td> |
| |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETCharDataGenerator</tt></td> |
| <td>Responsible for a part of the template translation process. Generates |
| strings for the character data present in the template file. Used by <tt class="code">JETCompiler</tt>.</td> |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETCompiler</tt></td> |
| |
| <td>This is the core class for template translation. This class is responsible |
| for translating templates to the Java source code of a template implementation |
| class. The actual translation is delegated to other classes in this package. |
| A <tt class="code">JETParser</tt> is used to parse the template into template elements. |
| <tt class="code">JETCompiler</tt> implements the <tt class="code">JETParseEventListener</tt> interface |
| and registers itself with the parser to be notified when the parser recognizes |
| a template element. For every recognized template element, <tt class="code">JETCompiler</tt> |
| uses a <tt class="code">JETGenerator</tt> to translate the template element to Java source |
| code. When the template parsing is complete, <tt class="code">JETCompiler</tt> uses a |
| <tt class="code">JETSkeleton</tt> to assemble the Java source code elements to a single |
| compilation unit (a Java class).</td> |
| |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETCompileTemplateOperation</tt></td> |
| <td>This class implements <tt class="code">org.eclipse.core.resources.IWorkspaceRunnable</tt> |
| so it can execute as a batch operation within the workspace. This operation |
| takes a workspace project, one or more Template Containers and optionally |
| a list of specific template files as constructor parameters. When its <tt class="code">run</tt> |
| method is invoked, it uses a <tt class="code">JETCompiler</tt> to translate the template |
| files in the specified workspace project folders to Java source files for |
| template implementation classes. This operation can optionally be configured |
| to trigger a complete build of the project when it is finished to compile |
| the Java source files to <i>.class</i> files.</td> |
| |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETConstantDataGenerator</tt></td> |
| <td>Responsible for a part of the template translation process. Extends <tt class="code">JETCharDataGenerator</tt> |
| to generate constant declarations for the strings with character data present |
| in the template file.</td> |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETCoreElement</tt></td> |
| |
| <td>Interface for core JET syntax elements (directive, expression, scriptlet |
| and quote-escape). Used by <tt class="code">JETParser</tt>.</td> |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETEmitter</tt></td> |
| <td>This class provides a convenient high-level API for users of this package. |
| The <tt class="code">generate</tt> method of this class translates a template to Java |
| source code, compiles this source code to a template implementation class, |
| asks the template class to generate text and finally returns the generated |
| result. This class creates a Java project called <i>.JETEmitters</i> in |
| the workspace, translates the template into this project, and simply calls |
| <tt class="code">build</tt> on the <i>.JETEmitters</i> project to compile the source |
| code. If translation or compilation fails, a <tt class="code">JETException</tt> is thrown. |
| A template implementation Java class is "executed" by calling its <tt class="code">generate</tt> |
| method.</td> |
| |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETException</tt></td> |
| <td>Extends <tt class="code">org.eclipse.core.runtime.CoreException</tt>, but provides |
| more convenient constructors.</td> |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETExpressionGenerator</tt></td> |
| |
| <td>Responsible for a part of the template translation process. Extends <tt class="code">JETScriptletGenerator</tt> |
| to translate JET expressions (<tt class="code"><%= ... %></tt> stuff) to Java source |
| code.</td> |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETGenerator</tt></td> |
| <td>Interface for generators: classes that know how to translate part of a |
| JET template to a Java source code element.</td> |
| |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETMark</tt></td> |
| <td>A state object used by the <tt class="code">JETParser</tt> to mark points in the JET |
| character input stream, and delegate the processing of parts of the stream |
| to other objects.</td> |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETNature</tt></td> |
| |
| <td> |
| <p>This class implements <tt class="code">IJETNature</tt> so that it can configure |
| a workspace project with the JET Nature. When this nature is added to |
| a project, it adds a JET Builder to the front of the build spec of the |
| project. This nature defines two properties: </p> |
| <ul> |
| <li> Template Containers - a list of folders in the project that contain |
| the JET templates to translate. </li> |
| <li>Source Container - the target folder in which to save translated template |
| implementation Java classes. </li> |
| </ul> |
| |
| <p>These properties are used by the JET Builder when performing a build.</p> |
| </td> |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETParseEventListener</tt></td> |
| <td>Interface for objects that know how to process parts of a JET character |
| input stream.</td> |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETParser</tt></td> |
| |
| <td>The main parser class. Has several inner classes for recognizing core |
| JET syntax elements (directive, expression, scriptlet and quote-escape). |
| When a core JET syntax element is recognized, the actual processing of the |
| element is delegated to a <tt class="code">JETParseEventListener</tt>.</td> |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETReader</tt></td> |
| <td>An input buffer for the JET parser. Provides a <tt class="code">stackStream</tt> method |
| that others can call with the character stream to an include file. Also |
| provides many other convenience methods for the parser.</td> |
| |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETScriptletGenerator</tt></td> |
| <td>Responsible for a part of the template translation process. Translates |
| JET scriptlets (<tt class="code"><% ... %></tt> stuff) to Java source code.</td> |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JETSkeleton</tt></td> |
| |
| <td>This class provides an interface for assembling Java source code elements |
| into a single Java compilation unit (a Java class). Java source code elements |
| are assembled according to a class skeleton definition. A skeleton can be |
| used to add boilerplate code to a translated template implementation class. |
| This class provides a default custom template implementation class skeleton |
| definition, but can also assemble Java elements using a custom skeleton. |
| The actual parsing and generation of Java source code is delegated to classes |
| in the <tt class="code">org.eclipse.jdt.core.jdom</tt> package.</td> |
| </tr> |
| </tbody> |
| </table> |
| <p></p> |
| <b>Package org.eclipse.emf.codegen.jmerge</b> |
| <p></p> |
| <table border="1" cellspacing="0"> |
| <tbody> |
| <tr> |
| <td><b>Class</b></td> |
| |
| <td><b>Description</b></td> |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JControlModel</tt></td> |
| <td>A control model that provides dictionaries and rules to drive a merge |
| process.</td> |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JMerger</tt></td> |
| |
| <td>A class for merging Java source files. Uses classes in the <tt class="code">org.eclipse.jdt.core.jdom</tt> |
| package to parse the source code. This class can be used by application |
| code, but can also be run as an Eclipse headless application.</td> |
| </tr> |
| <tr> |
| <td valign="top"><tt class="code">JPatternDictionary</tt></td> |
| <td>A dictionary of signatures and JDOM nodes.</td> |
| </tr> |
| |
| <tr> |
| <td valign="top"><tt class="code">PropertyMerger</tt></td> |
| <td>A class for merging property files. This class can be used by application |
| code, but can also be run as an Eclipse headless application.</td> |
| </tr> |
| </tbody> |
| </table> |
| <p></p> |
| <h3><a name="codegen_headless_application"></a>Running CodeGen as an Eclipse Headless |
| Application </h3> |
| <p>The <tt class="code">org.eclipse.emf.codegen.CodeGen</tt> class can translate a JET template to Java source code |
| and optionally merge the template implementation Java source code with an existing |
| Java class. CodeGen can be used as an Eclipse headless application ("headless" |
| means that the Eclipse GUI does not start). The <tt class="code">plugins/org.eclipse.emf.codegen/test</tt> |
| folder in your Eclipse installation contains some scripts for launching the |
| CodeGen class as an Eclipse headless application. These scripts are in Unix |
| format.</p> |
| |
| <p><img src="images/win_only.gif" width="49" height="13"/> Below is an example |
| script for Windows. Note that we pass two arguments to the CodeGen class:</p> |
| <ul> |
| <li>the <img src="images/tag_1.gif" width="24" height="13"/>uri of the template |
| to translate </li> |
| <li>the <img src="images/tag_2.gif" width="24" height="13"/>target path where |
| the translation result should be saved </li> |
| </ul> |
| <p>If the target path already contains a previous translation result, and you |
| want to merge the new translation result with the existing one, you can specify |
| a <tt class="code">JMerge</tt> control model file as the third argument. The <tt class="code">plugins/org.eclipse.emf.codegen/test</tt> |
| folder in your Eclipse installation contains an example <tt class="code">merge.xml</tt> file.</p> |
| |
| <pre class="code"> @echo off |
| set ECLIPSE_HOME=C:\eclipse-2.1\eclipse |
| set WORKSPACE=%ECLIPSE_HOME%\workspace |
| set OPTS=-Xmx900M -Djava.compiler=NONE -verify -cp %ECLIPSE_HOME%\startup.jar |
| set MAIN=org.eclipse.core.launcher.Main -noupdate -data %WORKSPACE% |
| |
| <img src="images/tag_1.gif" width="24" height="13"/>set TEMPLATE_URI=test.javajet |
| <img src="images/tag_2.gif" width="24" height="13"/>set TARGET_FOLDER=C:\temp\jetstandalone\MyProject |
| set ARGUMENTS=%TEMPLATE_URI% %TARGET_FOLDER% |
| |
| echo Shut down Eclipse before running this script. |
| java %OPTS% %MAIN% -application org.eclipse.emf.codegen.CodeGen %ARGUMENTS% |
| </pre> |
| <h3><a name="jetc"></a>jetc: An ANT Task for Translating JET Templates Outside |
| of Eclipse </h3> |
| <p>Author: Knut Wannheden (knut.wannheden at paranor.ch) </p> |
| <p>Binary: <a href="jetc-task.jar">jetc-task.jar</a>. </p> |
| <p>The source: <a href="JETCTask.java" target=_blank>JETCTask.java</a>.</p> |
| |
| <p>Some notes: </p> |
| <ul> |
| <li>In the <tt class="code"><taskdef/></tt> you have to specify the classpath to include |
| both this task as well as the jars of a number of Eclipse plug-ins (see the |
| example buildfile). </li> |
| <li>There are two ways to tell the jetc task which template(s) it should translate: |
| </li> |
| <ul> |
| <li>Use a nested fileset to specify the directory containing the template |
| files. </li> |
| |
| <li>Specify the template uri in the "template" attribute of the task. When |
| used this way, the task supports the "class" and "package" attributes which |
| overload the JET directives "class" and "package" in the template. It can |
| also be used if the JET directive is missing altogether. Use this attribute |
| when you want to specify the class to generate outside the template. </li> |
| </ul> |
| </ul> |
| <p>Here's a simple Ant buildfile (the taskdef classpath assumes you have Eclipse |
| 2.1 and EMF 1.1.0): </p> |
| <pre class="code"> <project default="jetc_multiple_templates"> |
| |
| <property name="eclipse.plugins.dir" location="C:/eclipse-2.1/eclipse/plugins"/> |
| |
| <taskdef name="jetc" classname="ch.paranor.epla.structure.JETCTask"> |
| |
| <classpath> |
| <pathelement location="jetc-task.jar"/> |
| <fileset dir="${eclipse.plugins.dir}"> |
| <include name="org.eclipse.core.boot_2.1.0/boot.jar"/> |
| <include name="org.eclipse.core.resources_2.1.0/resources.jar"/> |
| <include name="org.eclipse.core.runtime_2.1.0/runtime.jar"/> |
| |
| <include name="org.eclipse.emf.codegen_1.1.0/runtime/codegen.jar"/> |
| <include name="org.eclipse.jdt.core_2.1.0/jdtcore.jar"/> |
| </fileset> |
| </classpath> |
| </taskdef> |
| |
| <!-- Usage example 1: --> |
| |
| <!-- Specify the template file in the "template" attribute. --> |
| <!-- You can use the "class" and "package" attributes to override the --> |
| <!-- "class" and "package" attributes in the template file. --> |
| <target name="jetc_single_template"> |
| <mkdir dir="jet-output"/> |
| <jetc template="test.xmljet" package="com.foo" class="Test" destdir="jet-output"/> |
| |
| <javac srcdir="jet-output" destdir="classes"/> |
| </target> |
| |
| <!-- Usage example 2: --> |
| <!-- Translate a bunch of template files at once. --> |
| <!-- You cannot use the "class" and "package" attributes when using a fileset. --> |
| <target name="jetc_multiple_templates"> |
| |
| <mkdir dir="jet-output"/> |
| <jetc destdir="jet-output"> |
| <fileset dir="jet-templates" includes="*.*jet"/> |
| </jetc> |
| <javac srcdir="jet-output" destdir="classes"/> |
| </target> |
| |
| |
| </project></pre> |
| <h2>Resources </h2> |
| <p><a href="http://developer.java.sun.com/developer/Books/shiftintojava/page1.html#replaceenums" target="_blank">Substitutes |
| for Missing C Constructs</a> (By Joshua Bloch)</p> |
| <a href="http://www.javaworld.com/javaworld/javatips/jw-javatip122.html" target="_blank"> |
| Java Tip 122: Beware of Java typesafe enumerations</a> (By Vladimir Roubtsov)<br/> |
| <p><a href="http://www.javaworld.com/javaworld/javatips/jw-javatip133.html" target="_blank">Java |
| Tip 133: More on typesafe enums</a> (By Philip Bishop)</p> |
| |
| <p><a href="http://www.eclipse.org/emf/">http://www.eclipse.org/emf/ </a></p> |
| <p><small>Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun |
| Microsystems, Inc. in the United States, other countries, or both.</small></p> |
| </body> |
| </html> |