ConveniencePatterns ConveniencePatterns - 1 month ago 14
Java Question

How to generate EMF models with Java code

I want to generate EMF models with Java code. For example, I want to create a new Ecore Modeling Project, and the build a simple model as seen as in many Tutorials (i.e. like the vogella tutorial). But I don't want to do that by hand, using the GUI. I want to learn how to create a model with Java code, using the EMF-Ecore-API.

I tried to find tutorials about this topic. But to my disappointment, I couldn't find much about this topic. The only thing I could find was some code snippets to load and modify existing models by code. But nothing about creating new models. And just looking through the API did not help me.

Are there any sources on this topic? And if not, how can I create EMF models by java code?

Answer

IBM has a topic about dynamic EMF.

But it is pretty straight forward, if you're familiar with the way creation works in emf. Every EPackage has its own EFactory and EPackage Instances, which handle the creation (factory) or store information about the meta model itself (epackage).

Ecore has its own EPackage and EFactory so it's absolutely possible to create new meta-models on the fly like this:

    /*Use the Ecore factory*/
    EcoreFactory ecoreFactory = EcoreFactory.eINSTANCE;
    /*Create your EPackage*/
    EPackage myPackage = ecoreFactory.createEPackage();
    /*set EPackage properties*/
    myPackage.setName("myTest");
    myPackage.setNsPrefix("myTest");
    myPackage.setNsURI("http://com.myTest");

    /*Create your first EClass*/
    EClass myFirstEClass = ecoreFactory.createEClass();
    myFirstEClass.setName("myClass");
    /*Add to your EPackage's EClassifiers*/
    /*EClasses and EDatatypes implement both EClassifiers*/
    myPackage.getEClassifiers().add(myFirstEClass);

    /*Create your first EAtttribute*/
    EAttribute myFirstEAtt = ecoreFactory.createEAttribute();
    myFirstEAtt.setName("name");
    /*Use the EcorePackage Datatypes -> here EString*/
    myFirstEAtt.setEType(EcorePackage.eINSTANCE.getEString());
    /*use EStructuralFeatures to add your EAtt*/
    /*EReferences and EAttributes are both EStructuralfeatures*/
    myFirstEClass.getEStructuralFeatures().add(myFirstEAtt);

Update:

    /*Create your second EClass*/
    EClass mySecondEClass = ecoreFactory.createEClass();
    mySecondEClass.setName("mySecondClass");
    myPackage.getEClassifiers().add(mySecondEClass);

    /*now, the firstClass should hold instances of secondClass*/
    /*1. create EReference (Ereferences unlike EAttributes define relationships between EClasses)*/
    EReference secondClassesRef = ecoreFactory.createEReference();
    secondClassesRef.setName("secondClasses");
    /*set containment true -> every EObject must have a Container*/
    secondClassesRef.setContainment(true);
    /*set Type to your EClass*/
    secondClassesRef.setEType(mySecondEClass);
    /*set upperbound -> now the reference is an EList*/
    secondClassesRef.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY);

    /*finally add ERef to EClass*/
    myFirstEClass.getEStructuralFeatures().add(secondClassesRef);

    /*and for example supertypes*/
    myFirstEClass.getESuperTypes().add(mySecondEClass);

Now you have your own EPackage with a new EClass which has an EAttribute name of Type EString

Now it's also possible to save your new EPackage to an .ecore File like this:

    /*
     * Save your EPackage to file ecore file:
     */

    /*Initialize your EPackage*/
    myPackage.eClass();
    Resource.Factory.Registry reg = Resource.Factory.Registry.INSTANCE;
    Map<String, Object> m = reg.getExtensionToFactoryMap();
    /*add default .ecore extension for ecore file*/
    m.put(EcorePackage.eNAME, new XMIResourceFactoryImpl());

    // Obtain a new resource set
    ResourceSet resSet = new ResourceSetImpl();
    // create a resource
    Resource resource = null;
    try {
        resource = resSet.createResource(URI.createFileURI("/Your/Path/To/Directory/myTest.ecore"));
    } catch (Exception e) {
        e.printStackTrace();
    }
    /*add your EPackage as root, everything is hierarchical included in this first node*/
    resource.getContents().add(myPackage);

    // now save the content.
    try {
        resource.save(Collections.EMPTY_MAP);
    } catch (IOException e) {
        e.printStackTrace();
    }

and vice versa, if you want to load an existing ecore EPackage:

    /*
     * load existing EPackage
     */
    EcorePackage.eINSTANCE.eClass();
    /*Initialize your EPackage*/
    final Resource.Factory.Registry reg = Resource.Factory.Registry.INSTANCE;
    final Map<String, Object> m = reg.getExtensionToFactoryMap();
    m.put(EcorePackage.eNAME, new XMIResourceFactoryImpl());

    final ResourceSet resSet = new ResourceSetImpl();
    Resource resource = null;
    try {
        resource = resSet.getResource(URI.createFileURI("/Your/Path/To/Directory/myTest.ecore"), true);
    } catch (Exception e) {
        e.printStackTrace();
    }
    /*load root and cast to EPackage*/
    final EPackage root = (EPackage) resource.getContents().get(0);

Update: Ecore has of course its own meta-model. In the Docs you find a great overview of the ecore architecture.

So if you want to use dynamic EMF you need to understand this. As I showed you, it is very simple to create an EPackage dynamically, but you need to know how to set the basic attributes of the ecore model (EClass, EAttributes, EReferences, EType, containment, supertypes ...). Once you understood the architecture, then it is pretty easy. Have a look at the UML-Diagram at the bottom of the page.

I also updated the code above to show you how to initialize relations between EClasses