我创建了一个名为SimpleModelSerializer
的类,以便能够轻松地将EMF模型写入和读取到不同的格式中。使用readMemento
和writeMemento
方法处理IMemento
。该类可以轻松扩展以适用于其他格式。
它非常简洁,只能处理简单的模型。以下是一些限制:
- 不处理非包含引用。
- 不处理特征值的子类型化。
- EPackages必须在全局包注册表中。
- 它可能会在许多有效模型上崩溃。
- 不执行验证。
- 对扩展元数据的支持非常有限。
- 还有很多其他事情...
尽管如此,它对于保存小而简单的东西(如视图配置)非常有用。
这是代码:
public class SimpleModelSerializer {
public interface ModelReader {
List<String> getMultiAttribute(String name);
String getAttribute(String name);
String getDefaultAttribute(String name);
List<ModelReader> getChildren(String name);
}
public interface ModelWriter {
void setAttribute(String name, String value);
void setDefaultAttribute(String name, String value);
void setMultiAttribute(String name, List<String> values);
ModelWriter createChild(String name);
}
@SuppressWarnings("unchecked")
private static void setFeature(EObject o, EStructuralFeature feature, Object value) {
if (feature.isMany()) {
((List<Object>) o.eGet(feature)).add(value);
} else {
o.eSet(feature, value);
}
}
@SuppressWarnings("unchecked")
private static List<?> getFeature(EObject o, EStructuralFeature feature) {
if (feature.isMany()) {
return (List<Object>) o.eGet(feature);
} else {
return Collections.singletonList(o.eGet(feature));
}
}
public static <T extends EObject> T readMemento(IMemento mem, EClass cls, Class<T> instCls, ExtendedMetaData meta) {
return readCastedObject(cls, instCls, new MementoReader(mem), meta);
}
public static <T extends EObject> List<T> readMementos(IMemento mem, String name, EClass cls, Class<T> instCls, ExtendedMetaData meta) {
return readObjects(cls, instCls, new MementoReader(mem), name, meta);
}
public static <T extends EObject> List<T> readObjects(EClass cls, Class<T> instCls, ModelReader reader, String name, ExtendedMetaData meta) {
List<T> result = new ArrayList<>();
for (ModelReader childReader : reader.getChildren(name)) {
result.add(instCls.cast(readObject(cls, childReader, meta)));
}
return result;
}
public static <T extends EObject> T readCastedObject(EClass cls, Class<T> instCls, ModelReader reader, ExtendedMetaData meta) {
return instCls.cast(readObject(cls, reader, meta));
}
public static EObject readObject(EClass cls, ModelReader reader, ExtendedMetaData meta) {
if (meta == null) meta = ExtendedMetaData.INSTANCE;
EObject obj = EcoreUtil.create(cls);
for (EStructuralFeature feature : cls.getEAllStructuralFeatures()) {
if (feature.isTransient()) continue;
String name = meta.getName(feature);
List<Object> values = new ArrayList<>();
if (feature instanceof EAttribute) {
EAttribute attr = (EAttribute) feature;
List<String> attrs;
if (attr.isMany()) attrs = reader.getMultiAttribute(name);
else if (name.equals(":0")) attrs = singletonList(reader.getDefaultAttribute(name));
else attrs = singletonList(reader.getAttribute(name));
for (String attrText : attrs) {
if (attrText != null) {
values.add(EcoreUtil.createFromString(attr.getEAttributeType(), attrText));
}
}
} else if (feature instanceof EReference) {
EReference ref = (EReference) feature;
for (ModelReader childReader : reader.getChildren(name)) {
values.add(readObject(ref.getEReferenceType(), childReader, meta));
}
}
for (Object value : values) {
setFeature(obj, feature, value);
}
}
return obj;
}
public static void writeMemento(IMemento mem, EObject o, ExtendedMetaData meta) {
writeObject(new MementoWriter(mem), o, meta);
}
public static void writeMementos(IMemento mem, String childName, Collection<? extends EObject> os, ExtendedMetaData meta) {
MementoWriter writer = new MementoWriter(mem);
for (EObject o : os) {
writeObject(writer.createChild(childName), o, meta);
}
}
public static void writeObject(ModelWriter writer, EObject obj, ExtendedMetaData meta) {
if (meta == null) meta = ExtendedMetaData.INSTANCE;
EClass cls = obj.eClass();
for (EStructuralFeature feature : cls.getEAllStructuralFeatures()) {
if (feature.isTransient()) continue;
String name = meta.getName(feature);
if (feature instanceof EAttribute) {
List<String> outputValues = new ArrayList<>();
for (Object e : getFeature(obj, feature)) {
if (!Objects.equals(e, feature.getDefaultValue())) {
String textValue = EcoreUtil.convertToString((EDataType) feature.getEType(), e);
outputValues.add(textValue);
}
}
if (feature.isMany()) {
writer.setMultiAttribute(name, outputValues);
} else if (!outputValues.isEmpty()) {
if (name.equals(":0")) {
writer.setDefaultAttribute(name, outputValues.get(0));
} else {
writer.setAttribute(name, outputValues.get(0));
}
}
} else if (feature instanceof EReference) {
for (Object value : getFeature(obj, feature)) {
if (value != null) {
writeObject(writer.createChild(name), (EObject) value, meta);
}
}
}
}
}
private static class MementoReader implements ModelReader {
private final IMemento memento;
public MementoReader(IMemento memento) {
this.memento = memento;
}
@Override
public String getDefaultAttribute(String name) {
return memento.getTextData();
}
@Override
public String getAttribute(String name) {
return memento.getString(name);
}
@Override
public List<String> getMultiAttribute(String name) {
IMemento[] childMems = memento.getChildren(name);
List<String> attrs = new ArrayList<>(childMems.length);
for (IMemento mem : childMems) {
attrs.add(mem.getTextData());
}
return attrs;
}
@Override
public List<ModelReader> getChildren(String name) {
return Arrays.stream(memento.getChildren(name)).map(MementoReader::new).collect(toList());
}
}
private static class MementoWriter implements ModelWriter {
private final IMemento memento;
public MementoWriter(IMemento memento) {
this.memento = memento;
}
@Override
public void setAttribute(String name, String value) {
memento.putString(name, value);
}
@Override
public void setMultiAttribute(String name, List<String> values) {
for (String value : values) {
memento.createChild(name).putTextData(value);
}
}
@Override
public ModelWriter createChild(String name) {
return new MementoWriter(memento.createChild(name));
}
@Override
public void setDefaultAttribute(String name, String value) {
memento.putTextData(value);
}
}
}