Получить EClass из класса экземпляра модели EMF

Для любого объекта Class<?> clazz существует ли API для получения EClass, чьи экземпляры модели реализуют clazz? (т.е. eClass, для которого eClass.getInstanceClass().equals(clazz) верно)

Если бы у меня был eObject, я мог бы просто вызвать eObject.eClass(), чтобы получить EClass. Но в моем случае такого экземпляра у меня нет. У меня есть только класс экземпляра модели, и мне нужен связанный EClass для вызова EcoreUtil.create(eClass).


person kapex    schedule 08.06.2016    source источник
comment
Можете ли вы привести пример, где вы должны использовать это? Вы получаете clazz из obj.getClass(), где obj является экземпляром EObject, или вы получаете clazz, используя InterfaceName.class в своем коде (например, в UML, Activity.class)?   -  person Vincent Aranega    schedule 09.06.2016
comment
@VincentAranega Я использую InterfaceName.class, потому что на тот момент у меня не было obj. Он хочет предоставить метод create(InterfaceName.class) в качестве альтернативы create(eClass), потому что он может быть типобезопасным и, насколько мне известно, для получения EClass мне нужно либо получить его по имени (ePackage.getEClassifier("MyClass")), либо мне нужно будет использовать странные ссылки на MyPackage.Literals.MY_CLASS чего я хотел бы избежать   -  person kapex    schedule 09.06.2016
comment
Ладно ладно. Я думаю, что у меня есть решение для вас :) (я записываю это).   -  person Vincent Aranega    schedule 09.06.2016


Ответы (2)


Чтобы проиллюстрировать ответ, я предполагаю, что у нас есть метамодель с именем Foo, как в вашем предыдущем ответе, и что связанный пакет — FooPackage, а связанная фабрика — FooFactory. В этой метамодели я предполагаю, что у нас есть A и B, которые равны EClass.

Чтобы получить связанный EClass с A.class, вы можете использовать это:

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);
}

После этого вам нужно будет иметь дело с динамическими экземплярами (вашим EObject), если только вы явно не преобразуете myinstance в A, используя это:

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

Если вы поместите все это в метод, это может выглядеть так:

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
}

Обратите внимание, что на этом этапе вы должны быть уверены, что интерфейс, который вы пытаетесь создать (A.class), действительно является EClass и не является абстрактным, иначе будет возбуждено исключение.

Чтобы справляться с такими вещами, несколько месяцев назад я начал кодировать своего рода библиотеку для этого: https://github.com/aranega/dynemf

Это еще не полностью задокументировано, но вы можете делать такие вещи:

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

Вы можете просмотреть код, возможно, это может вам помочь.

Надеюсь, я правильно понял вашу проблему.

person Vincent Aranega    schedule 09.06.2016
comment
Спасибо! Однако это зависит от того, что имя модели идентично имени типа экземпляра, верно? Но это должно работать в большинстве случаев и, вероятно, будет работать для меня. - person kapex; 09.06.2016
comment
Да, это основано на том факте, что сгенерированное имя интерфейса точно такое же, как и то, которое вы смоделировали в своем .ecore. .getEClassifier(name) на EPackage является частью API EMF и обычно используется для работы с динамическими экземплярами (без необходимости генерировать код Java из вашего .ecore). Однако эти динамически-рефлексивные методы медленнее, чем их сгенерированные аналоги. - person Vincent Aranega; 09.06.2016

Я не мог найти никакого API для этого. Отношения между EClass и его классом экземпляра устанавливаются сгенерированными методами инициализатора, но нет никакого обратного сопоставления. Причина этого, по-видимому, в том, что нет связи один к одному, потому что несколько элементов модели могут использовать один и тот же интерфейс экземпляра.

Однако можно повторить все EClassifiers и построить отображение самостоятельно, если вы уверены, что каждый класс использует отдельный интерфейс.

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());
        }
    }
}
person kapex    schedule 09.06.2016