Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get EClass from EMF model instance class

Tags:

java

emf

Given any Class<?> clazz object, is there an API to get the EClass whose model instances implement clazz? (i.e. the eClass for which eClass.getInstanceClass().equals(clazz) is true)

If I had an eObject, I could simply call eObject.eClass() to get the EClass. But in my case I have no such instance. I only have a model instance class and need the associated EClass to call EcoreUtil.create(eClass).

like image 992
kapex Avatar asked Jan 24 '26 09:01

kapex


2 Answers

In order to illustrate the answer, I will asume that we have a metamodel called Foo as in your previous answer and that the associated package is FooPackage and the associated factory is FooFactory. In this metamodel I will suppose we have A and B which are EClass.

In order to get the associated EClass to a A.class, you can use this:

String aName = A.class.getSimpleName();
EClassifier classif = FooPackage.eInstance.getEClassifier(aName);
if (classif != null && classif instanceof EClass) {
  // At this point, you have the right EClass, 
  // you can now create an instance using the factory
  EObject myinstance = FooFactory.eInstance.create((EClass)classif);
}

After that, you will need to deal with dynamic instances (your EObject) unless you explicitally castmyinstance into an A using this:

A instance = (A) myinstance;
// or 
A instance = A.class.cast(myinstance);

If you put all of this in a method, it could look like this:

public static <T> T create(java.lang.Class<T> clazz) {
  String iName = clazz.getSimpleName();
  EClassif classif = FooPackage.eInstance.getEClassifier(iName);
  if (classif != null && classif instanceof EClass) {
    return clazz.cast(FooFactory.eInstance.create((EClass)classif));
  }
  return null; // or throw exception, clazz not found or stuff like that
}

Please note that at this point, you have to be sure that the interface you will try to create (A.class) is indeed EClass and is not abstract, otherwise an exception will be raised.

In order to handle this kind of stuffs, I began to code a kind of library for this few month ago: https://github.com/aranega/dynemf

It is not yet fully documented, but you can do stuffs like this:

EPackageWrapper mymm = ePackage(FooPackage.eINSTANCE);
mymm.create(A.class)
  .set("name", "MyAInstance")
  .set("bRels", mymm.create(B.class)
                  .set("name", "MyB1"));

You can browse the code, perhaps it could help you.

Hope I understood right your issue.

like image 119
Vincent Aranega Avatar answered Jan 26 '26 21:01

Vincent Aranega


I couldn't find any API for this. The relation between EClass and its instance class are set up by generated initializer methods but there isn't any reverse mapping. The reason for this seems to be be that there is no one-to-one relationship, because multiple model elements can use the same instance interface.

It's possible to iterate all EClassifiers and build a mapping yourself though, if you are sure that each class uses a distinct interface.

Map<Class<?>, EClass> eClasses = new HashMap<>();
for (final EClassifier eClassifier : FooPackage.eINSTANCE.getEClassifiers()) {
    if (eClassifier instanceof EClass) {
        if(eClasses.put(eClassifier.getInstanceClass(), (EClass) eClassifier) != null) {
            throw new RuntimeException(
                 "Failed to create distinct instance class to EClass mapping for "
                 + Classifier.getInstanceClass());
        }
    }
}
like image 37
kapex Avatar answered Jan 26 '26 21:01

kapex