从EMF模型实例类获取EClass

3
给定任何一个Class<?> clazz对象,是否有API可以获取实现clazz的模型实例的EClass?(即eClass.getInstanceClass().equals(clazz)为true的eClass
如果我有一个eObject,我只需调用eObject.eClass()即可获取EClass。但在我的情况下,我没有这样的实例。我只有一个模型实例类,并需要关联的EClass来调用EcoreUtil.create(eClass)

你能举个例子说明在什么情况下需要使用它吗?获取 clazz 是通过 obj.getClass() 来自 EObject 实例,还是在代码中使用 InterfaceName.class 来获取 clazz(例如:在 UML 中,Activity.class)? - Vincent Aranega
@VincentAranega 我使用 InterfaceName.class 是因为在那个时候我没有任何 obj。我想提供方法 create(InterfaceName.class) 作为 create(eClass) 的替代方案,因为它可以是类型安全的,并且据我所知,要获取 EClass,我需要通过名称获取它(ePackage.getEClassifier("MyClass")),或者我需要使用奇怪的引用 MyPackage.Literals.MY_CLASS,我希望避免这种情况。 - kapex
好的,好的。我想我有一个解决方案给你 :) (我正在记录下来)。 - Vincent Aranega
2个回答

6
为了说明答案,我将假设我们有一个名为Foo的元模型,就像你之前的回答一样,与之关联的包是FooPackage,关联的工厂是FooFactory。在这个元模型中,我假设我们有AB,它们都是EClass
要获取与A.class相关联的EClass,可以使用以下代码:
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"));

您可以浏览代码,也许可以帮助您。
希望我正确理解了您的问题。

谢谢!但是它依赖于模型名称与实例类型名称完全相同,对吗?不过在大多数情况下应该可以工作,并且可能适用于我。 - kapex
1
是的,它依赖于所生成的接口名称与您在 .ecore 中建模的接口名称完全相同的事实。EPackage 上的 .getEClassifier(name) 是 EMF API 的一部分,通常用于处理动态实例(无需从您的 .ecore 生成 Java 代码)。但是,这些“动态反射”方法比它们的生成对应方法慢。 - Vincent Aranega

2
我找不到任何与此相关的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());
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接