场合
我有一个Eclipse RCP应用程序,用于管理EMF模型中的应用程序项目。
通过将这些项目序列化为XMI格式来保存这些项目。然后可以将这些文件加载回模型中。我使用标准的EMF工具(例如Resource)。
由于模型重构,以下内容已更改:
MyClass
,其属性为Name
(带大写字母)。 <MyClass Name="My Class Name 1" ... />
VS
MyClass
继承自MyBaseClass
,属性name
(不带大写字母)。MyClass
不再具有Name
属性,因为EMF不允许这两者。这是有道理的,因为它会碰撞在例如getter方法getName()
。问题
如何将旧 XMI项目文件加载到 new 模型中?
直到这个问题,我能够:
但是,在这种情况下,我无法首先加载XMI文件:模型一方面错过属性name
而另一方面无法识别(因此忽略)属性Name
问题
实现此向后兼容性支持的正确位置是什么?
我假设我应该处理反序列化过程或XML映射。
解决方案的约束是:
<MyClass name="..." ... />
)也必须正确加载。答案 0 :(得分:3)
Ed Merks在EMF forums上解决了这个问题。
通过拦截XML映射来支持向后兼容性的最简单方法是在EMF资源上启用ExtendedMetaData
的实现。此类是调整EMF资源及其内容的中心入口点。它避免了必须专门化EMF框架内的各种其他类。
但是,我的项目已经有一个专门的XMLHelper
类,它处理XML序列化/反序列化,因此Ed Merks帮助解决了我在该类中的问题。
请注意,XMI XMLHelperImpl
source code显示了在资源上启用ExtendedMetaData
工具时如何调用它!
XMLHelper
/**
* Helper class that allows intercepting the XML to model mapping, to support backwards compatibility.
* <p>
* 2 methods must be overridden to handle compatibility mappings:
* <dl>
* <dt>{@link XMLHelperImpl#getFeature(EClass, String, String, boolean)}</dt>
* <dd>Is called to map features of a certain EClass. These include attributes and child elements in the XML file.</dd>
* <dt>{@link XMLHelperImpl#getType(EFactory, String)}</dt>
* <dd>Is called to map types that are used in the model.</dd>
* </dl>
* <p>
* Their difference becomes clear by looking at the model file. Sometimes both need to be handled. For example:
* <ul>
* <li>a {@link Person} has zero or more {@link Person#getPhoneNumber()} configurations ('feature')</li>
* <li>these features are of type {@link PhoneNumber} or possibly a subclass! ('type')</li>
* </ul>
* <p>
* See https://www.eclipse.org/forums/index.php/m/1449615/
*/
public class CustomXmlHelper extends XMLHelperImpl implements XMLHelper {
public CustomXmlHelper() {
super();
deresolve = true;
}
public CustomXmlHelper(XMLResource resource) {
super(resource);
deresolve = true;
}
@Override
public EStructuralFeature getFeature(EClass eClass, String namespaceURI, String name, boolean isElement) {
String compatName = name;
if (eClass == ProjectModelPackage.Literals.MyClass) {
if (!isElement && "Name".equals(name)) {
// 1.x to 2.x compatibility (October 2014)
// 1.x = MyClass attribute 'Name'
// 2.x = MyBaseClass attribute 'name', shared by MyClass
compatName = ProjectModelPackage.Literals.EMY_BASE_CLASS__NAME.getName(); // 'n(!)ame'
}
}
// future feature mappings handled here
return super.getFeature(eClass, namespaceURI, compatName, isElement);
}
@Override
public EClassifier getType(EFactory eFactory, String name) {
String compatName = name;
if (eFactory == ProjectModelPackage.eINSTANCE) {
// placeholder for type compatibility
// if ("OldTypeName".equals(name)) {
// compatName = ProjectModelPackage.Literals.NEW_TYPE_NAME.getName();
// }
}
return super.getType(eFactory, compatName);
}
}