EMF 实体序列化时出现 NotSerializableException

NotSerializableException on EMF entity serialization

我有 java 应用程序使用 EMF。我 运行 它在 WildFly 10 上。
我使用 Eclipse Neon 和 JDK8.0.
我将 EAR 部署到 WildFly 并对其进行调试。
我只需要将我的 EMF 审计 class 的实例序列化为 XML 字符串。
这是审计 class:

public class AuditImpl extends MinimalEObjectImpl.Container implements Audit {
    protected static final String OBJECT_ID_EDEFAULT = null;
    protected String object_id = OBJECT_ID_EDEFAULT;
    protected static final ObjectType OBJECT_TYPE_EDEFAULT = ObjectType.CLIENT;
    protected ObjectType object_type = OBJECT_TYPE_EDEFAULT;
    protected static final AuditAction ACTION_EDEFAULT = AuditAction.CREATE;
    protected AuditAction action = ACTION_EDEFAULT;
    protected static final Date ACTION_DATE_EDEFAULT = null;
    protected Date action_date = ACTION_DATE_EDEFAULT;
    protected static final Object NEW_VALUE_EDEFAULT = null;
    protected Object new_value = NEW_VALUE_EDEFAULT;
    protected AuditImpl() {
        super();
    }

    @Override
    protected EClass eStaticClass() {
        return NeoflexAuditPackage.Literals.AUDIT;
    }

    public String getObject_id() {
        return object_id;
    }

    public void setObject_id(String newObject_id) {
        String oldObject_id = object_id;
        object_id = newObject_id;
        if (eNotificationRequired())
            eNotify(new ENotificationImpl(this, Notification.SET, NeoflexAuditPackage.AUDIT__OBJECT_ID, oldObject_id, object_id));
    }

    public ObjectType getObject_type() {
        return object_type;
    }

    public void setObject_type(ObjectType newObject_type) {
        ObjectType oldObject_type = object_type;
        object_type = newObject_type == null ? OBJECT_TYPE_EDEFAULT : newObject_type;
        if (eNotificationRequired())
            eNotify(new ENotificationImpl(this, Notification.SET, NeoflexAuditPackage.AUDIT__OBJECT_TYPE, oldObject_type, object_type));
    }

    public AuditAction getAction() {
        return action;
    }

    public void setAction(AuditAction newAction) {
        AuditAction oldAction = action;
        action = newAction == null ? ACTION_EDEFAULT : newAction;
        if (eNotificationRequired())
            eNotify(new ENotificationImpl(this, Notification.SET, NeoflexAuditPackage.AUDIT__ACTION, oldAction, action));
    }

    public Date getAction_date() {
        return action_date;
    }

    public void setAction_date(Date newAction_date) {
        Date oldAction_date = action_date;
        action_date = newAction_date;
        if (eNotificationRequired())
            eNotify(new ENotificationImpl(this, Notification.SET, NeoflexAuditPackage.AUDIT__ACTION_DATE, oldAction_date, action_date));
    }

    public Object getNew_value() {
        return new_value;
    }

    public void setNew_value(Object newNew_value) {
        Object oldNew_value = new_value;
        new_value = newNew_value;
        if (eNotificationRequired())
            eNotify(new ENotificationImpl(this, Notification.SET, NeoflexAuditPackage.AUDIT__NEW_VALUE, oldNew_value, new_value));
    }

    @Override
    public Object eGet(int featureID, boolean resolve, boolean coreType) {
        switch (featureID) {
            case NeoflexAuditPackage.AUDIT__OBJECT_ID:
                return getObject_id();
            case NeoflexAuditPackage.AUDIT__OBJECT_TYPE:
                return getObject_type();
            case NeoflexAuditPackage.AUDIT__ACTION:
                return getAction();
            case NeoflexAuditPackage.AUDIT__ACTION_DATE:
                return getAction_date();
            case NeoflexAuditPackage.AUDIT__NEW_VALUE:
                return getNew_value();
        }
        return super.eGet(featureID, resolve, coreType);
    }

    @Override
    public void eSet(int featureID, Object newValue) {
        switch (featureID) {
            case NeoflexAuditPackage.AUDIT__OBJECT_ID:
                setObject_id((String)newValue);
                return;
            case NeoflexAuditPackage.AUDIT__OBJECT_TYPE:
                setObject_type((ObjectType)newValue);
                return;
            case NeoflexAuditPackage.AUDIT__ACTION:
                setAction((AuditAction)newValue);
                return;
            case NeoflexAuditPackage.AUDIT__ACTION_DATE:
                setAction_date((Date)newValue);
                return;
            case NeoflexAuditPackage.AUDIT__NEW_VALUE:
                setNew_value(newValue);
                return;
        }
        super.eSet(featureID, newValue);
    }

    @Override
    public void eUnset(int featureID) {
        switch (featureID) {
            case NeoflexAuditPackage.AUDIT__OBJECT_ID:
                setObject_id(OBJECT_ID_EDEFAULT);
                return;
            case NeoflexAuditPackage.AUDIT__OBJECT_TYPE:
                setObject_type(OBJECT_TYPE_EDEFAULT);
                return;
            case NeoflexAuditPackage.AUDIT__ACTION:
                setAction(ACTION_EDEFAULT);
                return;
            case NeoflexAuditPackage.AUDIT__ACTION_DATE:
                setAction_date(ACTION_DATE_EDEFAULT);
                return;
            case NeoflexAuditPackage.AUDIT__NEW_VALUE:
                setNew_value(NEW_VALUE_EDEFAULT);
                return;
        }
        super.eUnset(featureID);
    }

    @Override
    public boolean eIsSet(int featureID) {
        switch (featureID) {
            case NeoflexAuditPackage.AUDIT__OBJECT_ID:
                return OBJECT_ID_EDEFAULT == null ? object_id != null : !OBJECT_ID_EDEFAULT.equals(object_id);
            case NeoflexAuditPackage.AUDIT__OBJECT_TYPE:
                return object_type != OBJECT_TYPE_EDEFAULT;
            case NeoflexAuditPackage.AUDIT__ACTION:
                return action != ACTION_EDEFAULT;
            case NeoflexAuditPackage.AUDIT__ACTION_DATE:
                return ACTION_DATE_EDEFAULT == null ? action_date != null : !ACTION_DATE_EDEFAULT.equals(action_date);
            case NeoflexAuditPackage.AUDIT__NEW_VALUE:
                return NEW_VALUE_EDEFAULT == null ? new_value != null : !NEW_VALUE_EDEFAULT.equals(new_value);
        }
        return super.eIsSet(featureID);
    }

    @Override
    public String toString() {
        if (eIsProxy()) return super.toString();

        StringBuffer result = new StringBuffer(super.toString());
        result.append(" (object_id: ");
        result.append(object_id);
        result.append(", object_type: ");
        result.append(object_type);
        result.append(", action: ");
        result.append(action);
        result.append(", action_date: ");
        result.append(action_date);
        result.append(", new_value: ");
        result.append(new_value);
        result.append(')');
        return result.toString();
    }

} //AuditImpl

这是我的函数:

private String getXml(Audit audit) throws NeoflexException {
    XMLResource res = new XMLResourceImpl();        
    res.getContents().add(audit);       
    StringWriter sw = new StringWriter();

    try {
        res.save(sw, null);
    } catch (IOException e) {
        throw new NeoflexException(e);
    }

    return sw.toString();   
}

开res.save(sw, null);我得到:

java.lang.RuntimeException: java.io.NotSerializableException: NeoflexAudit.impl.AccountImpl
org.eclipse.emf.ecore.impl.EFactoryImpl.convertToString(EFactoryImpl.java:692)
org.eclipse.emf.ecore.impl.EcoreFactoryImpl.convertEJavaObjectToString(EcoreFactoryImpl.java:937)
org.eclipse.emf.ecore.impl.EcoreFactoryImpl.convertToString(EcoreFactoryImpl.java:209)
org.eclipse.emf.ecore.xmi.impl.XMLHelperImpl.convertToString(XMLHelperImpl.java:1610)
org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl.getDatatypeValue(XMLSaveImpl.java:3108)
org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl.saveDataTypeSingle(XMLSaveImpl.java:1698)
org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl.saveFeatures(XMLSaveImpl.java:1280)
org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl.saveFeatures(XMLSaveImpl.java:1224)
org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl.saveElementID(XMLSaveImpl.java:2716)
org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl.writeTopObject(XMLSaveImpl.java:683)
org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl.traverse(XMLSaveImpl.java:591)
org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl.save(XMLSaveImpl.java:225)

编辑

好的,我看到 class 必须是可序列化的,但我无法通过 EMF 建模视图实现它...并且编辑生成的代码是错误的。
所以我将函数更改为:

private void persistAudit(Audit audit) throws NeoflexException {
    ResourceSet resourceSet = new ResourceSetImpl();
    resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xml", new XMLResourceFactoryImpl());

    URI fileURI = URI.createFileURI(new File("mypo.xml").getAbsolutePath());
    Resource poResource = resourceSet.createResource(fileURI);
    poResource.getContents().add(audit);

    try {
        poResource.save(null);
    } catch (IOException e) {
        throw new NeoflexException(e);
    }
}

我用过:

resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xml", new XMLResourceFactoryImpl());

如此处所述:"Registered factory needed" exception when loading resource
但是我在 poResource 中仍然有 null。

Class NeoflexAudit.impl.AccountImpl 必须实施 Serializable.

一般来说,序列化 class 及其内部成员(也嵌套)必须实现 Serializable 接口才能使序列化工作。

资源工厂方法是必经之路。我唯一缺少的是 ResourceSet 还需要了解您的元模型:class 和属性信息是持久化模型所必需的。

所提供的方法使用 StringWritter,因此您实际上可以获得带有 XML 的字符串(可能需要发送您的回复;))

private String getAuditXML(Audit audit) throws NeoflexException {
    ResourceSet resourceSet = new ResourceSetImpl();
    // In standalone we need to register the Ecore metamodel too
    EcorePackage.eINSTANCE.eClass();
    // From your post I assume yuo have the generated EPackage of your metamodel,
    // if not you need to load the ecore file as a resource too, get the EPackage and
    // register it
    AuditPackage.eINSTANCE.eClass();
    // Ecore models should be persisted as XMI (which is just an XML document
    // with an additional namesapce, so it should work for you).
    resourceSet.getResourceFactoryRegistry()
        .getExtensionToFactoryMap()
        .put("xmi", new XMIResourceFactoryImpl());
    // Since we are creating a stirng, not actually persisting to a file, we will use a
    // "dummy" uri, just make sure it uses the correct extension
    URI fileURI = URI.createURI("audit.xmi");
    Resource poResource = resourceSet.createResource(fileURI);
    poResource.getContents().add(audit);
    // Save to a string writter so we can get the string
    StringWriter outputWriter = new StringWriter();
    try {
        poResource.save(outputWriter, null);
    } catch (IOException e) {
        throw new NeoflexException(e);
    }
    return outputWriter.toString();
}

虽然这种方法有一个巨大的警告:AFAIK EMF 不支持部分模型的持久性。因此,如果您的 Audit 对象不是完整模型的根,您可能会出错。也就是说,审计包含层次结构中的对象中的所有非包含引用都指向所述层次结构中的对象。

如果 Audit 不是根源,则可能出现错误的原因是 EMF 的包含语义。如果 Audit 对象不是根,则将其分配给资源的内容将有效地将其从之前的包含中移除。一种可能的解决方法是存储引用并在创建 XML 字符串后恢复它,行中的内容为:

EObject container = audit.eContainer;
// Serialize
audit.eContainer = container;    // Not so easy, you probably need to save the feature that provided the containment too

审核包含树之外的引用更难。您可能需要考虑创建自己的 XMI 资源工厂来处理部分模型。