Nevertheless As I tried to use that setup, I ran into a few problems.
- Transferring a 0...* reference causes an Exception: java.util.ArrayList ([...]) cannot be assigned to org.eclipse.emf.common.util.EList
- Registered Adapters (EObjectImpl:eAdapters) can not be passed over the wire and causes Exception
- In some cases I had trouble transferring the EObjectImpl:eProperties attribute
Through extension points I can register my own EObjectSerializerFactory which uses my Deserialiser/Serializer for all EObjects.
My classes need to be in a "common" plug-in which is active on the server and client.
Both the EObjectSerializer and EObjectDeserializer are based on the JavaSerializer/JavaDeserializer provided by Caucho.
Basiclly all I do, is serializing the content of the EStructuralFeatures instead of serializing the Java fields.
So this way eFlags, eAdapters, eContainer, eContainerFeatureID and eProperties (EObjectImpl fields) are not passed over the wire.
I my case this works since I don't need the eContainer on the server.
Here the classes, maybe they help you to use the same combination:
EObjectSerializerFactory.java
/*******************************************************************************
* $URL: $
*
* Copyright (c) 2007 henzler informatik gmbh, CH-4106 Therwil
*******************************************************************************/
package com.softmodeler.service.communication;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import com.caucho.hessian.io.AbstractSerializerFactory;
import com.caucho.hessian.io.Deserializer;
import com.caucho.hessian.io.HessianProtocolException;
import com.caucho.hessian.io.Serializer;
/**
* EObjectSerializerFactory, provides a serializer and deserializer for EObjects
*
* @see EObjectSerializer
* @see EObjectDeserializer
* @author created by Author: fdo, last update by $Author: fdo $
* @version $Revision: 1236 $, $Date: 2009-03-03 22:51:32 +0100 (Di, 03 Mrz 2009) $
*/
public class EObjectSerializerFactory extends AbstractSerializerFactory {
/** class name suffix for implemented EClassifiers */
private static final String CLASS_SUFFIX = "Impl"; //$NON-NLS-1$
/** packages that should be excluded from reading */
private static final String[] EXCLUDE_PACKAGE_NS_URI = new String[] { "http://www.eclipse.org/emf/2002/Ecore" }; //$NON-NLS-1$
/** internal cache of all EClassifiers existing in the system, ClassifierName=>EClassifier */
private MapallClassifiers = null;
/**
* Returns a map with all relevant EClassifiers
*
* @return map ClassifierName=>EClassifier
*/
private MapgetAllClassifiers() {
if (allClassifiers == null) {
allClassifiers = new HashMap();
// iterate the EPackages and place all classifiers in the allClassifiers map
for (Object value : EPackage.Registry.INSTANCE.values()) {
if (value instanceof EPackage) {
EPackage ePackage = (EPackage) value;
if (isValidPackage(ePackage.getNsURI())) {
for (EClassifier eClassifier : ePackage.getEClassifiers()) {
allClassifiers.put(eClassifier.getName(), eClassifier);
}
}
}
}
}
return allClassifiers;
}
/**
* Returns true if the package is valid (not in the EXCLUDE_PACKAGE_NS_URI list)
*
* @param nsURI the package NameSpace URI
* @return true if valid
*/
private boolean isValidPackage(String nsURI) {
for (String excludePackage : EXCLUDE_PACKAGE_NS_URI) {
if (excludePackage.equals(nsURI)) {
return false;
}
}
return true;
}
/**
* Returns the EClassifier for the passed Class
*
* @param cl
* @return returns null if the class is not an EObject or not found in the EPackages
*/
@SuppressWarnings("unchecked")
private EClass getClassifier(Class cl) {
if (EObject.class.isAssignableFrom(cl)) {
String name = cl.getSimpleName();
if (name.endsWith(CLASS_SUFFIX)) {
EClassifier classifier = getAllClassifiers().get(name.substring(0, name.indexOf(CLASS_SUFFIX)));
if (classifier instanceof EClass) {
return (EClass) classifier;
}
}
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public Deserializer getDeserializer(Class cl) throws HessianProtocolException {
EClass classifier = getClassifier(cl);
if (classifier != null) {
return new EObjectDeserializer(classifier);
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public Serializer getSerializer(Class cl) throws HessianProtocolException {
EClass classifier = getClassifier(cl);
if (classifier != null) {
return new EObjectSerializer(classifier);
}
return null;
}
}
EObjectSerializer.java
/*******************************************************************************
* $URL: $
*
* Copyright (c) 2007 henzler informatik gmbh, CH-4106 Therwil
*******************************************************************************/
package com.softmodeler.service.communication;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.impl.EObjectImpl;
import com.caucho.hessian.io.AbstractHessianOutput;
import com.caucho.hessian.io.AbstractSerializer;
import com.caucho.hessian.io.JavaSerializer;
/**
* Serializes EObjects, this class is based on the {@link JavaSerializer} instead of working with java fields,
* {@link EStructuralFeature} are used to serialize the 'data' values of the {@link EObject}.
* Java fields of the {@link EObjectImpl}; eAdapters, eFlags, eContainer, eContainerFeatureID and eProperties are
* ignored
*
* @see JavaSerializer
* @author created by Author: fdo, last update by $Author: fdo $
* @version $Revision: 1151 $, $Date: 2009-02-25 22:47:19 +0100 (Mi, 25 Feb 2009) $
*/
public class EObjectSerializer extends AbstractSerializer {
private ListfieldSerializers;
private Listfields;
/**
* constructor
*
* @param classifier
*/
@SuppressWarnings("unchecked")
public EObjectSerializer(EClass classifier) {
fields = classifier.getEAllStructuralFeatures();
fieldSerializers = new ArrayList();
for (EStructuralFeature feature : fields) {
if (!feature.isMany()) {
EClassifier eDataType = feature.getEType();
Class type = eDataType.getInstanceClass();
fieldSerializers.add(getFieldSerializer(type));
} else {
fieldSerializers.add(ListFieldSerializer.SER);
}
}
}
@SuppressWarnings("unchecked")
@Override
public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
if (out.addRef(obj)) {
return;
}
Class cl = obj.getClass();
int ref = out.writeObjectBegin(cl.getName());
if (ref < -1) { writeObject10((EObject) obj, out); } else { if (ref == -1) { writeDefinition20(out); out.writeObjectBegin(cl.getName()); } writeInstance((EObject) obj, out); } } private void writeObject10(EObject obj, AbstractHessianOutput out) throws IOException { for (int i = 0; i < feature =" fields.get(i);" i =" 0;" feature =" fields.get(i);" ser =" new" value =" null;" value =" obj.eGet(feature);" ser =" new" value =" false;" value =" (Boolean)" ser =" new" value =" 0;" value =" (Integer)" ser =" new" value =" 0;" value =" (Long)" ser =" new" value =" 0;" value =" (Double)" ser =" new" value =" null;" value =" (String)" ser =" new" value =" null;" objvalue =" (List)" value =" new">
EObjectDeserializer.java
/*******************************************************************************
* $URL: $
*
* Copyright (c) 2007 henzler informatik gmbh, CH-4106 Therwil
*******************************************************************************/
package com.softmodeler.service.communication;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.impl.EObjectImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import com.caucho.hessian.io.AbstractHessianInput;
import com.caucho.hessian.io.AbstractMapDeserializer;
import com.caucho.hessian.io.HessianFieldException;
import com.caucho.hessian.io.IOExceptionWrapper;
import com.caucho.hessian.io.JavaDeserializer;
/**
* Deserializes EObjects, this class is based on the {@link JavaDeserializer} instead of working with java fields,
* {@link EStructuralFeature} are used to deserialize the 'data' values of the {@link EObject}.
* Java fields of the {@link EObjectImpl}; eAdapters, eFlags, eContainer, eContainerFeatureID and eProperties are
* ignored
*
* @see JavaDeserializer
* @author created by Author: fdo, last update by $Author: fdo $
* @version $Revision: 1236 $, $Date: 2009-03-03 22:51:32 +0100 (Di, 03 Mrz 2009) $
*/
public class EObjectDeserializer extends AbstractMapDeserializer {
private MapfieldMap;
private EClass classifier;
/**
* constructor
*
* @param classifier
*/
public EObjectDeserializer(EClass classifier) {
this.classifier = classifier;
fieldMap = getFieldMap(classifier);
}
@SuppressWarnings("unchecked")
@Override
public Class getType() {
return classifier.getInstanceClass();
}
@Override
public Object readMap(AbstractHessianInput in) throws IOException {
try {
EObject obj = instantiate();
return readMap(in, obj);
} catch (IOException e) {
throw e;
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new IOExceptionWrapper(classifier.getName() + ":" + e.getMessage(), e); //$NON-NLS-1$
}
}
@Override
public Object readObject(AbstractHessianInput in, String[] fieldNames) throws IOException {
try {
Object obj = instantiate();
return readObject(in, (EObject) obj, fieldNames);
} catch (IOException e) {
throw e;
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new IOExceptionWrapper(classifier.getName() + ":" + e.getMessage(), e); //$NON-NLS-1$
}
}
public Object readMap(AbstractHessianInput in, EObject obj) throws IOException {
try {
int ref = in.addRef(obj);
while (!in.isEnd()) {
Object key = in.readObject();
FieldDeserializer deser = fieldMap.get(key);
if (deser != null) {
deser.deserialize(in, obj);
} else {
in.readObject();
}
}
in.readMapEnd();
in.setRef(ref, obj);
return obj;
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOExceptionWrapper(e);
}
}
public Object readObject(AbstractHessianInput in, EObject obj, String[] fieldNames) throws IOException {
try {
int ref = in.addRef(obj);
for (String name : fieldNames) {
FieldDeserializer deser = fieldMap.get(name);
if (deser != null) {
deser.deserialize(in, obj);
} else {
in.readObject();
}
}
in.setRef(ref, obj);
return obj;
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOExceptionWrapper(obj.getClass().getName() + ":" + e, e); //$NON-NLS-1$
}
}
/**
* create an instance of the passed classifier
*
* @return
* @throws Exception
*/
protected EObject instantiate() throws Exception {
return EcoreUtil.create(classifier);
}
/**
* Creates a map featureName=>FieldDeserializer.
*/
@SuppressWarnings("unchecked")
protected MapgetFieldMap(EClass classifier) {
MapfieldMap = new HashMap ();
for (EStructuralFeature feature : classifier.getEAllStructuralFeatures()) {
if (feature.isTransient() || fieldMap.containsKey(feature.getName())) {
continue;
}
FieldDeserializer deser;
EClassifier eDataType = feature.getEType();
Class type = eDataType.getInstanceClass();
if (String.class.equals(type)) {
deser = new StringFieldDeserializer(feature);
} else if (byte.class.equals(type)) {
deser = new ByteFieldDeserializer(feature);
} else if (short.class.equals(type)) {
deser = new ShortFieldDeserializer(feature);
} else if (int.class.equals(type)) {
deser = new IntFieldDeserializer(feature);
} else if (long.class.equals(type)) {
deser = new LongFieldDeserializer(feature);
} else if (float.class.equals(type)) {
deser = new FloatFieldDeserializer(feature);
} else if (double.class.equals(type)) {
deser = new DoubleFieldDeserializer(feature);
} else if (boolean.class.equals(type)) {
deser = new BooleanFieldDeserializer(feature);
} else if (feature.isMany()) {
deser = new EListDeserializer(feature);
} else {
deser = new ObjectFieldDeserializer(feature);
}
fieldMap.put(feature.getName(), deser);
}
return fieldMap;
}
abstract static class FieldDeserializer {
protected EStructuralFeature feature;
public FieldDeserializer(EStructuralFeature feature) {
this.feature = feature;
}
abstract void deserialize(AbstractHessianInput in, EObject obj) throws IOException;
}
static class EListDeserializer extends FieldDeserializer {
EListDeserializer(EStructuralFeature feature) {
super(feature);
}
@SuppressWarnings("unchecked")
@Override
void deserialize(AbstractHessianInput in, EObject obj) throws IOException {
List value = null;
try {
value = (List) in.readObject(List.class);
if (value.size() > 0) {
obj.eSet(feature, value);
}
} catch (Exception e) {
logDeserializeError(feature, obj, value, e);
}
}
}
static class ObjectFieldDeserializer extends FieldDeserializer {
ObjectFieldDeserializer(EStructuralFeature feature) {
super(feature);
}
@Override
void deserialize(AbstractHessianInput in, EObject obj) throws IOException {
Object value = null;
try {
value = in.readObject(feature.getEType().getInstanceClass());
if (value != null) {
obj.eSet(feature, value);
}
} catch (Exception e) {
logDeserializeError(feature, obj, value, e);
}
}
}
static class BooleanFieldDeserializer extends FieldDeserializer {
BooleanFieldDeserializer(EStructuralFeature feature) {
super(feature);
}
@Override
void deserialize(AbstractHessianInput in, EObject obj) throws IOException {
boolean value = false;
try {
value = in.readBoolean();
obj.eSet(feature, value);
} catch (Exception e) {
logDeserializeError(feature, obj, value, e);
}
}
}
static class ByteFieldDeserializer extends FieldDeserializer {
ByteFieldDeserializer(EStructuralFeature feature) {
super(feature);
}
@Override
void deserialize(AbstractHessianInput in, EObject obj) throws IOException {
int value = 0;
try {
value = in.readInt();
obj.eSet(feature, value);
} catch (Exception e) {
logDeserializeError(feature, obj, value, e);
}
}
}
static class ShortFieldDeserializer extends FieldDeserializer {
ShortFieldDeserializer(EStructuralFeature feature) {
super(feature);
}
@Override
void deserialize(AbstractHessianInput in, EObject obj) throws IOException {
int value = 0;
try {
value = in.readInt();
obj.eSet(feature, value);
} catch (Exception e) {
logDeserializeError(feature, obj, value, e);
}
}
}
static class IntFieldDeserializer extends FieldDeserializer {
IntFieldDeserializer(EStructuralFeature feature) {
super(feature);
}
@Override
void deserialize(AbstractHessianInput in, EObject obj) throws IOException {
int value = 0;
try {
value = in.readInt();
obj.eSet(feature, value);
} catch (Exception e) {
logDeserializeError(feature, obj, value, e);
}
}
}
static class LongFieldDeserializer extends FieldDeserializer {
LongFieldDeserializer(EStructuralFeature feature) {
super(feature);
}
@Override
void deserialize(AbstractHessianInput in, EObject obj) throws IOException {
long value = 0;
try {
value = in.readLong();
obj.eSet(feature, value);
} catch (Exception e) {
logDeserializeError(feature, obj, value, e);
}
}
}
static class FloatFieldDeserializer extends FieldDeserializer {
FloatFieldDeserializer(EStructuralFeature feature) {
super(feature);
}
@Override
void deserialize(AbstractHessianInput in, EObject obj) throws IOException {
double value = 0;
try {
value = in.readDouble();
obj.eSet(feature, value);
} catch (Exception e) {
logDeserializeError(feature, obj, value, e);
}
}
}
static class DoubleFieldDeserializer extends FieldDeserializer {
DoubleFieldDeserializer(EStructuralFeature feature) {
super(feature);
}
@Override
void deserialize(AbstractHessianInput in, EObject obj) throws IOException {
double value = 0;
try {
value = in.readDouble();
obj.eSet(feature, value);
} catch (Exception e) {
logDeserializeError(feature, obj, value, e);
}
}
}
static class StringFieldDeserializer extends FieldDeserializer {
StringFieldDeserializer(EStructuralFeature feature) {
super(feature);
}
@Override
void deserialize(AbstractHessianInput in, EObject obj) throws IOException {
String value = null;
try {
value = in.readString();
obj.eSet(feature, value);
} catch (Exception e) {
logDeserializeError(feature, obj, value, e);
}
}
}
static void logDeserializeError(EStructuralFeature feature, Object obj, Object value, Throwable e)
throws IOException {
String fieldName = (feature.getContainerClass().getName() + "." + feature.getName()); //$NON-NLS-1$
if (e instanceof HessianFieldException) {
throw (HessianFieldException) e;
} else if (e instanceof IOException) {
throw new HessianFieldException(fieldName + ": " + e.getMessage(), e); //$NON-NLS-1$
}
if (value != null) {
throw new HessianFieldException(fieldName + ": " + value.getClass().getName() + " (" + value + ")" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ " cannot be assigned to " + feature.getEType().getName()); //$NON-NLS-1$
} else {
throw new HessianFieldException(fieldName + ": " + feature.getEType().getName() //$NON-NLS-1$
+ " cannot be assigned from null", e); //$NON-NLS-1$
}
}
}