Home > Xtext > Xtend2 Code Generators with Non-Xtext Models

Xtend2 Code Generators with Non-Xtext Models

In this blog post i want to show a simple example of how to use Xtend2 to generate code from Non-Xtext but EMF-based model.

Having a simple EMF Model i’ve created the genmodel + Model + Edit + Editor code.
Using the Editor i’ve created a bunch of .sample files and now want to
generate code using Xtend2.

Xtend comes with an IGenerator interface that i implement in my SampleGenerator Xtend file

package sample

import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.xtext.generator.IGenerator
import org.eclipse.xtext.generator.IFileSystemAccess
import org.eclipse.emf.ecore.EObject

class SampleGenerator implements IGenerator {

	override void doGenerate(Resource resource, IFileSystemAccess fsa) {
		for (EObject o : resource.contents) {
			o.compile(fsa)
		}
	}

	def dispatch void compile(Model m, IFileSystemAccess fsa) {
		for (e : m.elements) {
			e.compile(fsa)
		}
	}

	def compile(Element e, IFileSystemAccess fsa) {
		fsa.generateFile(e.name+".txt", '''
		this is element «e.name»
		''')
	}

	def dispatch void compile(EObject m, IFileSystemAccess fsa) { }

}

The last step we need is a workflow that reads the model files and invokes the generator

First we need to create some java classes that exposes our .sample to the reader
(resourceseriveprovider) and
do some Guice Binding Stuff (Generator / ResourceSet ….)

package sample;

import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.xtext.generator.IGenerator;
import org.eclipse.xtext.resource.generic.AbstractGenericResourceRuntimeModule;

public class SampleGeneratorModule extends AbstractGenericResourceRuntimeModule {

	@Override
	protected String getLanguageName() {
		return "sample.presentation.SampleEditorID";
	}

	@Override
	protected String getFileExtensions() {
		return "sample";
	}

	public Class<? extends IGenerator> bindIGenerator() {
		return SampleGenerator.class;
	}

	public Class<? extends ResourceSet> bindResourceSet() {
		return ResourceSetImpl.class;
	}

}

 

package sample;

import org.eclipse.xtext.ISetup;

import com.google.inject.Guice;
import com.google.inject.Injector;

public class SampleGeneratorSetup implements ISetup {

	@Override
	public Injector createInjectorAndDoEMFRegistration() {
		return Guice.createInjector(new SampleGeneratorModule());
	}

}

 

package sample;

import org.eclipse.xtext.resource.generic.AbstractGenericResourceSupport;

import com.google.inject.Module;

public class SampleGeneratorSupport extends AbstractGenericResourceSupport {

	@Override
	protected Module createGuiceModule() {
		return new SampleGeneratorModule();
	}

}

finally we wire this together in the workflow file

module sample.SampleGenerator

import org.eclipse.emf.mwe.utils.*

var targetDir = "src-gen"
var modelPath = "model"

Workflow {

	bean = StandaloneSetup {
		registerGeneratedEPackage = "sample.SamplePackage"
	}

	component = DirectoryCleaner {
		directory = targetDir
	}

	component = sample.SampleGeneratorSupport {}

	component = org.eclipse.xtext.mwe.Reader {
		path = modelPath
		register = sample.SampleGeneratorSetup {}
		loadResource = {
			slot = "model"
		}
	}

	component = org.eclipse.xtext.generator.GeneratorComponent {
		register = sample.SampleGeneratorSetup {}
		slot = 'model'
		outlet = {
			path = targetDir
		}
	}
}

running the workflow we get nice files generated

Advertisements
Categories: Xtext Tags: , ,
  1. July 29, 2011 at 21:03

    Thanks again, Christian! This is a very valuable article for me.

    ~Karsten

  2. Andy
    August 5, 2011 at 09:13

    Hi Christian,
    I just came to xtext/xtend2 some weeks ago, now we have created a xtext project successfully, we want to build the whole project with ant, now we have a problem with compile the xtend file to java code, as in Eclipse, when save the xtend file, it will generate the java file accordingly, but how could we do it by ant.

    By the we we can use org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher with the mwe2 file to generate the files under src-gen, but this process has no effect with the xtend file generation.

    Any help will be appreciated.

    • August 5, 2011 at 09:31

      Hi, there are basically 3 problems that make this currently impossible
      (1) there are bugs that prevent a proper programmatically reading of Xtend files in Standalone code
      (2) you would have to write the gluecode that calls Xtend compiler yourself
      (3) if you mix java and Xtend code in both directions you get errors unless you use a sophisticated java compiler like that from eclipse jdt

      So short solution: check in generated java classes too as everybody even the Xtext guys does
      Karsten Thoms is working on a solution for maven. Maybe the Xtext guys come with a Standalone solution too. Feel free to commit something yourself. And file or comment on tickets in bugzilla

  3. August 5, 2011 at 10:09

    1) is solved for Xtext 2.0.1
    For 2) I have written a WorkflowComponent and workflow that I will publish at xtext-utils
    I am currently stuck with problem 3). The example build works if executed 3 times
    – 1. compile Java -> fails with missing Xtend Java classes
    – 2. compile Xtend, but does not invoke the Java compiler
    – 3. compile the rest

    My experimental code is here:
    https://github.com/kthoms/org.eclipse.xtext.example.domainmodel/tree/tycho
    (I’m depending on Minerva as parent, which is missing there)

  4. Andy
    August 8, 2011 at 07:18

    Thank you for the reply.

    Yes I also tried to use xtendcomiler in a standalone java code to compile the xtend file to java code, but it only works with xtend files which have no dependencies to other java sources, as you all mentioned in case 3, there will be problems even I add the reference jave sources to the ResourceSet.

    I think it seems there’s no other choice but submit all generated java code currently. Hope there’s a solution soon.

  5. August 8, 2011 at 07:26

    It does work also with Xtend code referencing Java code that must be compiled before, but not in one execution process right now. If you execute the process 3 times as described it would work. But this is of course a no go.

    I’m still investigating this in my spare time.

    • Andy
      August 8, 2011 at 09:32

      Hi Thoms,

      My xtend file does some generation for my DSL, it refers to some java files generated in the src-gen folder, I refer to your code here https://github.com/kthoms/org.eclipse.xtext.example.domainmodel/tree/tycho/org.eclipselabs.xtext.xtend2/src/org/eclipselabs/xtext/xtend2/compiler, I change my workflow as CompileXtend.mwe2, add add XtendCompilerComponent.java to my generator package, but run with errors like:

      Caused by: java.lang.UnsupportedOperationException
      at java.util.AbstractCollection.add(Unknown Source)
      at org.eclipse.xtext.mwe.ResourceLoadingSlotEntry.addUri(ResourceLoadingSlotEntry.java:43)
      … 43 more

      I don’t know what have I missed.
      By the way, I don’t find the reference to the java resources in your code, how do you compile them and use them for xtend file, I am new to xtext/xtend, maybe I miss something, more detail explanation will be appreciated.

      • August 8, 2011 at 10:51

        I will likely blog about this once I have solved the problem. This is just an intermediate result so far. Before transferring the POMs to your project you should first try to get this example running like you intend to use it later. As said, it would only work when compile is executed 3 times so far.

        Kind regards,
        ~Karsten

  6. December 22, 2011 at 01:11

    Hi, thanks for this post which is very helpful.

    Now if someone go here and try to make it work with an xml model persistence (rather than xmi), it can save you some time :

    In the GeneratorModule class, change the method :
    public Class bindResourceSet() {
    Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
    “mymodel”, new MyModelResourceFactoryImpl());
    return ResourceSetImpl.class;
    }

    Adapting “mymodel” to match the file extension and the ResourceFactoryImpl to the one generated in EMF model projet.

  7. Srini
    May 14, 2012 at 04:40

    Awesome stuff. I spent whole day to get it work, finally this page did the trick.
    Thanks a lot and keep up the good work.

  8. Robert
    August 8, 2012 at 11:45

    That’s exactly what I want do do, but I don’t get it work.
    I have an ecor-based model created with the generated editor plugin, but if I try to create a new Xtext-Project eclipse crashes. Creating a new Xtext-project without my editor plugin is no problem.
    Do you have any suggestions to solve my problem?

    • August 8, 2012 at 11:47

      Hi habe you an error message?

      • Robert
        August 8, 2012 at 11:56

        Yes: “!ENTRY org.eclipse.e4.ui.workbench 4 0 2012-08-08 13:52:35.364
        !MESSAGE Unable to create class ‘org.eclipse.ui.internal.e4.compatibility.CompatibilityEditor’ from bundle ‘458’
        !STACK 0
        org.eclipse.e4.core.di.InjectionException:
        java.lang.OutOfMemoryError: PermGen space”
        in my exlipse.ini I have configured now:
        openFile
        –launcher.XXMaxPermSize
        org.eclipse.platform
        –launcher.XXMaxPermSize
        1024m
        -Xmx1500m

        Or do I have to confige it at another place for my plugin?

      • August 8, 2012 at 12:00

        Hi you have To set -XX:MaxPermSize To a higher value e.g. 128m

      • Robert
        August 8, 2012 at 12:11

        I have tested now up to 1024m, but it’s still crashing.
        I recognised, that the project is generated, but if I try to open the click on “Project_>clean…” it crashes again:
        Exception in thread “Worker-0” Exception in thread “Worker-2”
        !ENTRY org.eclipse.equinox.util 4 0 2012-08-08 14:08:48.194
        !MESSAGE Unable to create more threads!

      • August 8, 2012 at 12:15

        Hi there seems to be something wrong with your mom settings can you please post the JVM arcs of your launch cfg. Btw these messages are not Xtext specific so Google might help – 1024 is to much anywat

      • Robert
        August 8, 2012 at 12:35

        Im not shure what exactly the problem was, but I got it work with the 32bit edition of eclipse.

      • Robert
        August 9, 2012 at 12:16

        Finally solved the problem by adding MaxPermSize as VM-argument uner Run -> Run Configuration to “-XX:MaxPermSize=128m”

  9. Nixon Moreno
    August 17, 2012 at 01:18

    Hey. I am new to this area and am trying to replicate the tutorial without success, let me know if you can help me?
    I create the emf proyect with ecore model and genmodel, but when I create the xtend file, this file does not recognize model in the line 16.

    Thanks and sorry for the wording

  10. Nixon Moreno
    August 19, 2012 at 19:51

    Hi did you generate the model code from the gen model?
    yes I did, I generate the model code, edit code and editor code,
    and after I export the project like a eclipse plugin to generate the a.sample file.

    Thanks and sorry for the wording

  11. August 19, 2012 at 21:05

    HI,

    make sure your model project is on the classpath of the generator project

  12. Nixon Moreno
    August 22, 2012 at 02:35

    Hi,
    I´m not sure that the plugins is on the classpath, I have a question the generator project what kind is ? Xtext, Empty Emf or other ?.
    I’ll check the classpath.

    Thanks and sorry for the wording.

    • August 22, 2012 at 06:21

      Hi it should be a plugin project with Xtext nature and Xtend libs added to the required bundles

  13. Robert
    August 29, 2012 at 09:55

    I want to execute an own extra validator before generating where I can check some special things of the model. Cann you tell me what the best practice is to do that?

    • August 31, 2012 at 18:48

      Hi,

      one possibility would be to (eager) bind an AbstractDeclarativeValidator as Xtext does it.
      but i never tried this myself.

  14. Nixon Moreno
    August 30, 2012 at 01:16

    I create the plugin project, I add the xtext nature and Xtend/Xpand nature in the project, but in the classpath dont have the plugins that I export and the emf plugins.

    Thanks and sorry for the wording.

    • August 31, 2012 at 18:44

      Hi you need the java classes for your emf model and these java classes have to be on the classpath of the generator project. sorry this is all what i can say from this far distance.

  15. denis
    April 4, 2013 at 09:24

    Any hints how I can get this working using .uml as model?

  16. May 8, 2013 at 12:29

    Hi Christian,

    thank you for this blog post, it helped me in the beginning. But working with it made me wonder, isn’t there an easier way to accomplish this?
    I think you don’t need the workflow and all the extra java classes.
    I found this: http://stackoverflow.com/questions/12458852/load-emf-model-instance-in-xtend
    It works and loads the model perfectly. The only downside I didn’t find is how to write files like you do.
    I can use a java FileWriter, but the files won’t be added to my java Project. Do you know by chance how I can use something like the IFileSystemAcceess you are using?

    Thank you!
    Best Regards Joerg

  17. May 12, 2013 at 11:18

    Hi Christian,

    I tried a bit and I think I mixed something up with my last post.
    So generally speaking, I want a code generator like in xtext, Your post only states so that I can work with the MWE2 and generate my code with right click on that all the time.
    Is it possible to do that like in the 15 minutes extended Tutorial from xtext?
    So basically I just want to have an plugin which runs my Generator when I change a file in the src folder.

    Thank you for your help.
    Best Regards Joerg

  18. May 12, 2013 at 11:18

    Hi,

    I tried a bit and I think I mixed something up with my last post.
    So generally speaking, I want a code generator like in xtext, Your post only states so that I can work with the MWE2 and generate my code with right click on that all the time.
    Is it possible to do that like in the 15 minutes extended Tutorial from xtext?
    So basically I just want to have an plugin which runs my Generator when I change a file in the src folder.

    Thank you for your help.
    Best Regards Joerg

    • May 15, 2013 at 19:27

      Hi,

      first you could try to implement a eclipse builder
      (nothing todo with Xtext, you may use XtextBuilder as inspiration)
      another point would be to reuse xtexts XtextBuilder
      together with a IXtextBuilderParticipant and IResourceDescriptionStrategy but i dont know if that works

  19. denis
    June 5, 2013 at 11:21

    Hi,
    thank you very much for this article. I have finally have it working with uml. Now I need a write-once behavior to implement a generation gap pattern. I understand that I need to implement an IOutputConfigurationProvider for this purpose. However, all examples and instructions tell me to add this to the UiModule. Do you have any suggestions how to use IOutputConfigurationProvider with your example to make a write-once behavior work?

    thanks!

    • June 5, 2013 at 11:28

      Doing the provider should also work standalone. Sorry that I don’t have the time to come with an example.
      If not this is a bug missing feature in generatorcomponent

      • denis
        June 5, 2013 at 11:57

        Hi,

        thanks for your quick reply. I have added a typical implementation of IOutputConfigurationProvider in GeneratorModule:
        public void configure(Binder binder) {
        super.configure(binder);

        binder.bindIOutputConfigurationProvider.class).toExtendedOutputConfigurationProviderForComponentGen.class). in(Singleton.class);
        }

        I am now able to use output configurations. However, it ignores setOverrideExistingResources(false) and overwrites the generated files every time. Am I missing something or is this a bug?

        thanks!

      • June 5, 2013 at 12:05

        Hi please debug generator component and filesystemaccess

  20. denis
    June 6, 2013 at 07:29

    Hi,

    thanks for your hints. I have debugged into JavaIoFileSystemAccess and it seems not to care at all about configurations from IOutputConfigurationProvider – I think about submitting a bug. I have extended JavaIoFileSystemAccess, bound it (binder.bind()) in GeneratorModule.configure():

    public class SmartFileSystemAccess extends JavaIoFileSystemAccess {
    public void generateFile(String fileName, String outputConfigName, CharSequence contents) {
    OutputConfiguration outputConfig = getOutputConfig(outputConfigName);
    File file = getFile(fileName, outputConfigName);
    if(file.exists() && outputConfig.isOverrideExistingResources()) {
    super.generateFile(fileName, outputConfigName, contents);
    }

    thanks a lot!

  21. alexej.lotz@arcor.de
    June 11, 2013 at 11:38

    Hi Christian,

    thank you for your wonderful blog post. Similar to denis, I am trying to generate code from uml using xtend2 as you propose. After some efforts using this tutorial: https://christiandietrich.wordpress.com/2011/07/17/xtext-2-0-and-uml/

    I have finally managed to generate code using xtend2 out of pure uml. However, in my project I need to use UML Profiles. When using UML Profiles the stereotypes are not accessible in my Xtend class. I searched a lot of forums and the only reply I get (if any) is that xtend2 does not support UML Profiles any more (as e.g. it was possible in the old OAW). In OAW I needed to introduce the UML Profile inside the workflow to the generator component. How to do this within your example? Do you maybe have any further hints on this?

    Thank you,
    Alex

    • June 11, 2013 at 11:42

      Hi am not sure if this is Xtext specific. Maybe the uml forum can help. Are the profile thinks totally not available (reflection)

      • Alex
        June 11, 2013 at 11:54

        Hi,

        Thank you for your fast reply!

        I do not use xtext at all in this case. Is there any xtext relation that is hidden under the hood?

        In my uml profile, for instance, I extend the UML::Component class with my own stereotype lets call it MyComponent. In my Xtend class I can see the UML::Component but not the stereotype MyComponent. So if I have several custom component types I can not distinguish them. Any ideas?

        Thanks,
        Alex

      • June 11, 2013 at 11:56

        Hi I think you have to ask the uml things for their applied stereotypes

    • Tom
      July 10, 2015 at 10:31

      Dear Alexej, could you please give me a pointer how you have managed to generate code directly from UML? I am also trying an analog case, in which I need to generate code from BPMN models. They are based on EMF, but you can’t generate any model (edit, editor, etc.) code, so this really good approach can’t be used directly. Best regards!

      • July 10, 2015 at 10:41

        hi you should not need that. so what is your actual problem

      • Tom
        July 10, 2015 at 15:57

        Dear Christian, I need a similar approach as you have blogged. What I am trying to achieve is to generate some code using Xtend from BPMN models, which do not have any user-generated model code as in user-modeled EMF instances. So, your other post with UML2 was helpful in the beginning for mapping the plugin-model tools to the platform resources. But referencing a non-Xtext-based model from my DSL is also not the exact same thing I want to do. I don’t have a DSL in that matter at all. I just need the capabilities of Xtend to traverse the BPMN model instances and generate further code for specific content elements in these models. What is the best approach for doing this? My experiences with code generation were based more on using directly Xtext DSLs and then using Xtend as an extension of Java to generate code from my DSL instances. Thanks and regards. Tom

      • July 10, 2015 at 15:59

        which bpmn framework do you use? and emf based?

        class Main {

        def static void main(String[] args) {
        val f = new Bpmn2ResourceFactoryImpl
        //val f = new Bpmn2XMIResourceFactoryImpl
        val p = Bpmn2Package.eINSTANCE
        Resource.Factory.Registry.INSTANCE
        .extensionToFactoryMap.put(“bpmn”, f)
        val rs = new ResourceSetImpl
        val r = rs.getResource(URI.createURI(“SampleProcess.bpmn”),true)
        r.load(null)
        println(”’
        «FOR c : r.contents»
        «IF c instanceof DocumentRoot»
        «IF c.definitions != null»
        «c.definitions.rootElements»
        «ENDIF»
        «ENDIF»
        «ENDFOR»
        ”’)
        }

        }

      • Tom
        July 12, 2015 at 13:19

        Dear Christian, thanks for the pointer. It is the BPMN2 modeler framework ( http://www.eclipse.org/bpmn2-modeler/ ), which is indeed based on the EMF metamodel (BMPN20.ecore).

        Using EMF Resource framework I am able to traverse the model instance from which I want to generate different codes based on various model elements of this instance. But how am I supposed to the organize the code generation without having a workflow? I need this workflow to define my e.g. components to define the folder structure of the generated codes etc.

        Thanks,
        Tom

      • July 12, 2015 at 13:25

        You are notsupposed to do anything. Do whatever you want. Workflow or java main. You might even write your own wf components

      • August 4, 2015 at 04:37

        you can do the same with a java main

  22. Alex
    June 11, 2013 at 12:33

    Hi,

    ok, I think I can get the idea you are referring to. As far as I understand I need to use the org.eclipse.uml2.uml.util.UMLUtil similar to this:

    def getMyComponent(org.eclipse.uml2.uml.Component comp) {
    if(comp.isStereotypeApplied(“profile::MyComponent”) {
    var mc = ProfileFactory::eINSTANCE.createMyComponent
    var cl = UMLUtil::getTaggedValue(comp, “profile::MyComponent”, “SomeComponentProperty”)
    if (cl instanceof org.eclipse.uml2.uml.Class) {
    mc.setSomeComponentProperty(cl as org.eclipse.uml2.uml.Class)
    // …
    }
    return mc
    }
    return null
    }

    In other words I have to create my stereotype instances myself by hand (or to write a custom generator for my generator ;-)). That seems to do the trick, even so imho it is not quite user friendly 🙂

    Thanks,
    Alex

  23. Ambreen
    November 16, 2017 at 15:51

    Hi Christian, Thanks for your article. It really helped. It worked perfectly. But after I wrote OCL constraints for my ecore Model. I am getting error
    ERROR Mwe2Launcher – Problems running workflow : Validation problems:
    Unable to find delegate to evaluate the constraint
    Any help in that would be great. Many Thanks

    • November 17, 2017 at 07:57

      Hi, i have no idea on that. can you please ask in the EMF forum at eclipse

  1. August 5, 2016 at 03:07

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: