Using Xpand in Your Eclipse Wizards

DZone 's Guide to

Using Xpand in Your Eclipse Wizards

· Java Zone ·
Free Resource

At ESE, I had a nice chat with Chris (actually, I had a lot of nice chats with a lot of nice people - it was quite a challenge to attend any of the sessions), who told me that he was looking into template engines. I leave it up to you to make any assumptions on why he's interested in template engines. I happen to know at least three template engines: Velocity (which I had the joy of using in my active days at AndroMDA.org), the template, erhm, ... mechanism being used in PDE (I once fixed a bug which had been caused by this engine) and - you might have guessed it - Xpand (which I am a committer on).

So, I gave a short demo of Xtext and Xpand to show Chris how easy it is to create (model-aware) code generation templates. Xpand comes with a nice editor which makes template editing a joy - it features code highlighting, hyperlink navigation, model-awareness and other editor goodness.

Instead of letting only Chris know how that works, here's a short guide on how to write your own Xpand template and use it in a wizard. To make the example more realistic, I chose to implement a wizard that creates an Ant build.xml file for a simple project (something which is missing in Eclipse, AFAIK). So, here we go.


How to do it

  1. Download and install the prerequisites.
  2. Create a new plug-in project named "de.peterfriese.antwizard"
  3. Add a New File Wizard to the project. I used the Custom plug-in Wizard to get me started.
  4. Brush up the wizard page and add some fields for project name, source folder and binary folder.
  5. We want to transfer the values entered in this wizard into our template, so we need to create an Ecore model that describes our data model.
  6. Add org.eclipse.emf and org.eclipse.emf.edit to the dependencies of you plug-in.
  7. Create a genmodel and let EMF generate the model code for you.
  8. Add code to your wizard that transfers the values from the input fields to your model. One might consider using databinding for doing this, I used a straight forward read'n'write approach for the time being:
    public boolean performFinish() {
        final String containerName = page.getContainerName();
        final String srcDirName = page.getSrcDirName();
        final String binDirName = page.getBinDirName();
        // ...
    private BuildSpecification createModel(IProject project, String srcDirName,
        String binDirName) {
        BuildSpecification buildSpecification = BuildspecificationFactory.eINSTANCE.createBuildSpecification();
        Project projectSpecification = BuildspecificationFactory.eINSTANCE.createProject();
        return buildSpecification;
  9. Create an Xpand template de.peterfriese.antwizard/src/template/BuildTemplate.xpt:


    Ant file template

    In case you wonder how to get those funky characters: make sure us create this file using the Xpand editor - it has code assist (CTRL + space) for those characters.

  10. Create an Xtend file de.peterfriese.antwizard/src/template/GeneratorExtensions.ext:


    Ant file extensions
  11. Add org.eclipse.xpand, org.eclipse.xtend and org.eclipse.xtend.typesystem.emf to the depencies of your plug-in.
  12. Finally, we need to provide some code to invoke the generator:
    private void generate(BuildSpecification buildSpec, IProgressMonitor monitor) throws CoreException {
        // get project root folder as absolute file system path
        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
        IResource resource = root.findMember(new Path(buildSpec.getProject().getName()));
        String containerName = resource.getLocation().toPortableString();
        // configure outlets
        OutputImpl output = new OutputImpl();
        Outlet outlet = new Outlet(containerName);
        // create execution context
        Map globalVarsMap = new HashMap();
        XpandExecutionContextImpl execCtx = new XpandExecutionContextImpl(output, null, globalVarsMap, null, null);
        EmfRegistryMetaModel metamodel = new EmfRegistryMetaModel() {
            protected EPackage[] allPackages() {
                return new EPackage[] { BuildspecificationPackage.eINSTANCE, EcorePackage.eINSTANCE };
        // generate
        XpandFacade facade = XpandFacade.create(execCtx);
        String templatePath = "template::BuildTemplate::main";
        facade.evaluate(templatePath, buildSpec);
        // refresh the project to get external updates:
        resource.refreshLocal(IResource.DEPTH_INFINITE, monitor);

That's it!

Taking it for a spin

  1. Launch a runtime workbench by selecting de.peterfriese.antwizard/META-INF/MANIFEST.MF and invoking Run As -> Eclipse Application
  2. Create a new Java project in the runtime workspace.
  3. Invoke your wizard by selecting File -> New -> Other... -> Ant -> Ant build file from existing project
  4. Enter the required information (project name, source folder, binariy folder)
  5. After clicking on finish, you should get a fresh Ant file for your project:


    Ant file
  6. Enjoy!

You can download the project here. Feedback and comments are welcome!


From http://www.peterfriese.de


Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}