Title: [2334] branches/v-1.4.x: Merge deprecation of SerializationMethodInvoker from trunk.

Diff

Property changes: branches/v-1.4.x


Modified: svn:mergeinfo

+ /trunk:2151-2152,2154-2156,2158-2163,2165,2172,2175,2177,2188-2189,2197,2199-2201,2204,2206,2210,2212,2214-2217,2226,2229,2231,2233-2234,2236-2238,2247-2249,2279-2280,2285,2291-2292,2294,2298-2299,2301,2303,2306-2310,2312,2314,2316-2318,2320,2322,2324,2326,2329,2333

Modified: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java (2333 => 2334)


--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java	2015-02-14 16:44:43 UTC (rev 2333)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java	2015-02-15 02:37:22 UTC (rev 2334)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2004, 2005, 2006 Joe Walnes.
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 XStream Committers.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -22,6 +22,7 @@
 import com.thoughtworks.xstream.core.util.FastField;
 import com.thoughtworks.xstream.core.util.HierarchicalStreams;
 import com.thoughtworks.xstream.core.util.Primitives;
+import com.thoughtworks.xstream.core.util.SerializationMembers;
 import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
@@ -47,13 +48,19 @@
 
     protected final ReflectionProvider reflectionProvider;
     protected final Mapper mapper;
+    /**
+     * @deprecated As of upcoming, use {@link #serializationMembers}.
+     */
+    @Deprecated
     protected transient SerializationMethodInvoker serializationMethodInvoker;
+    protected transient SerializationMembers serializationMembers;
     private transient ReflectionProvider pureJavaReflectionProvider;
 
     public AbstractReflectionConverter(Mapper mapper, ReflectionProvider reflectionProvider) {
         this.mapper = mapper;
         this.reflectionProvider = reflectionProvider;
         serializationMethodInvoker = new SerializationMethodInvoker();
+        serializationMembers = serializationMethodInvoker.serializationMembers;
     }
     
     protected boolean canAccess(Class type) {
@@ -68,7 +75,7 @@
 
     public void marshal(Object original, final HierarchicalStreamWriter writer,
         final MarshallingContext context) {
-        final Object source = serializationMethodInvoker.callWriteReplace(original);
+        final Object source = serializationMembers.callWriteReplace(original);
 
         if (source != original && context instanceof ReferencingMarshallingContext) {
             ((ReferencingMarshallingContext)context).replace(original, source);
@@ -255,7 +262,7 @@
         final UnmarshallingContext context) {
         Object result = instantiateNewInstance(reader, context);
         result = doUnmarshal(result, reader, context);
-        return serializationMethodInvoker.callReadResolve(result);
+        return serializationMembers.callReadResolve(result);
     }
 
     public Object doUnmarshal(final Object result, final HierarchicalStreamReader reader,
@@ -560,6 +567,7 @@
 
     protected Object readResolve() {
         serializationMethodInvoker = new SerializationMethodInvoker();
+        serializationMembers = serializationMethodInvoker.serializationMembers;
         return this;
     }
 

Modified: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java (2333 => 2334)


--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java	2015-02-14 16:44:43 UTC (rev 2333)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java	2015-02-15 02:37:22 UTC (rev 2334)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014 XStream Committers.
+ * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014, 2015 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -407,7 +407,7 @@
         if (result == null) {
             result = create(enhancer, callbacks, useFactory);
         }
-        return serializationMethodInvoker.callReadResolve(result);
+        return serializationMembers.callReadResolve(result);
     }
 
     private void readCallback(HierarchicalStreamReader reader, UnmarshallingContext context,

Modified: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java (2333 => 2334)


--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java	2015-02-14 16:44:43 UTC (rev 2333)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java	2015-02-15 02:37:22 UTC (rev 2334)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2004, 2005, 2006 Joe Walnes.
- * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014 XStream Committers.
+ * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2013, 2014, 2015 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -21,9 +21,10 @@
 import com.thoughtworks.xstream.core.util.CustomObjectInputStream;
 import com.thoughtworks.xstream.core.util.CustomObjectOutputStream;
 import com.thoughtworks.xstream.core.util.HierarchicalStreams;
+import com.thoughtworks.xstream.core.util.SerializationMembers;
+import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
-import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
 import com.thoughtworks.xstream.mapper.Mapper;
 
 import java.io.Externalizable;
@@ -44,7 +45,7 @@
 
     private Mapper mapper;
     private final ClassLoaderReference classLoaderReference;
-    private transient SerializationMethodInvoker serializationMethodInvoker;
+    private transient SerializationMembers serializationMembers;
 
     /**
      * Construct an ExternalizableConverter.
@@ -56,7 +57,7 @@
     public ExternalizableConverter(Mapper mapper, ClassLoaderReference classLoaderReference) {
         this.mapper = mapper;
         this.classLoaderReference = classLoaderReference;
-        serializationMethodInvoker = new SerializationMethodInvoker();
+        serializationMembers = new SerializationMembers();
     }
 
     /**
@@ -78,7 +79,7 @@
     }
 
     public void marshal(final Object original, final HierarchicalStreamWriter writer, final MarshallingContext context) {
-        final Object source = serializationMethodInvoker.callWriteReplace(original);
+        final Object source = serializationMembers.callWriteReplace(original);
         if (source != original && context instanceof ReferencingMarshallingContext) {
             ((ReferencingMarshallingContext)context).replace(original, source);
         }
@@ -165,7 +166,7 @@
             CustomObjectInputStream objectInput = CustomObjectInputStream.getInstance(context, callback, classLoaderReference);
             externalizable.readExternal(objectInput);
             objectInput.popCallback();
-            return serializationMethodInvoker.callReadResolve(externalizable);
+            return serializationMembers.callReadResolve(externalizable);
         } catch (NoSuchMethodException e) {
             throw new ConversionException("Cannot construct " + type.getClass() + ", missing default constructor", e);
         } catch (InvocationTargetException e) {
@@ -182,7 +183,7 @@
     }
 
     private Object readResolve() {
-        serializationMethodInvoker = new SerializationMethodInvoker();
+        serializationMembers = new SerializationMembers();
         return this;
     }
 }

Modified: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java (2333 => 2334)


--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java	2015-02-14 16:44:43 UTC (rev 2333)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java	2015-02-15 02:37:22 UTC (rev 2334)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2004, 2005, 2006 Joe Walnes.
- * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2012, 2013, 2014 XStream Committers.
+ * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2012, 2013, 2014, 2015 XStream Committers.
  * All rights reserved.
  *
  * The software in this package is published under the terms of the BSD
@@ -33,9 +33,9 @@
 import com.thoughtworks.xstream.core.util.CustomObjectInputStream;
 import com.thoughtworks.xstream.core.util.CustomObjectOutputStream;
 import com.thoughtworks.xstream.core.util.HierarchicalStreams;
+import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
-import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
 import com.thoughtworks.xstream.mapper.Mapper;
 
 /**
@@ -75,6 +75,7 @@
 
     /**
      * Construct a SerializableConverter.
+     *
      * @param mapper the mapper chain instance
      * @param reflectionProvider the reflection provider
      * @param classLoaderReference the reference to the {@link ClassLoader} of the XStream instance
@@ -107,7 +108,7 @@
         if (type != null
             && Serializable.class.isAssignableFrom(type)
             && !type.isInterface()
-            && (serializationMethodInvoker.supportsReadObject(type, true) || serializationMethodInvoker
+            && (serializationMembers.supportsReadObject(type, true) || serializationMembers
                 .supportsWriteObject(type, true))) {
             for (Iterator iter = hierarchyFor(type).iterator(); iter.hasNext();) {
                 if (!Serializable.class.isAssignableFrom((Class)iter.next())) {
@@ -246,7 +247,7 @@
                         marshalUnserializableParent(writer, context, source);
                         mustHandleUnserializableParent = false;
                     }
-                    if (serializationMethodInvoker.supportsWriteObject(currentType[0], false)) {
+                    if (serializationMembers.supportsWriteObject(currentType[0], false)) {
                         writtenClassWrapper[0] = true;
                         writer.startNode(mapper.serializedClass(currentType[0]));
                         if (currentType[0] != mapper.defaultImplementationOf(currentType[0])) { 
@@ -256,10 +257,10 @@
                             }
                         }
                         CustomObjectOutputStream objectOutputStream = CustomObjectOutputStream.getInstance(context, callback);
-                        serializationMethodInvoker.callWriteObject(currentType[0], source, objectOutputStream);
+                        serializationMembers.callWriteObject(currentType[0], source, objectOutputStream);
                         objectOutputStream.popCallback();
                         writer.endNode();
-                    } else if (serializationMethodInvoker.supportsReadObject(currentType[0], false)) {
+                    } else if (serializationMembers.supportsReadObject(currentType[0], false)) {
                         // Special case for objects that have readObject(), but not writeObject().
                         // The class wrapper is always written, whether or not this class in the hierarchy has
                         // serializable fields. This guarantees that readObject() will be called upon deserialization.
@@ -390,7 +391,7 @@
             }
 
             public void defaultReadObject() {
-                if (serializationMethodInvoker.getSerializablePersistentFields(currentType[0]) != null) {
+                if (serializationMembers.getSerializablePersistentFields(currentType[0]) != null) {
                     readFieldsFromStream();
                     return;
                 }
@@ -452,10 +453,10 @@
                 } else {
                     currentType[0] = mapper.realClass(classAttribute);
                 }
-                if (serializationMethodInvoker.supportsReadObject(currentType[0], false)) {
+                if (serializationMembers.supportsReadObject(currentType[0], false)) {
                     CustomObjectInputStream objectInputStream = 
                         CustomObjectInputStream.getInstance(context, callback, classLoaderReference);
-                    serializationMethodInvoker.callReadObject(currentType[0], result, objectInputStream);
+                    serializationMembers.callReadObject(currentType[0], result, objectInputStream);
                     objectInputStream.popCallback();
                 } else {
                     try {

Modified: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java (2333 => 2334)


--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java	2015-02-14 16:44:43 UTC (rev 2333)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java	2015-02-15 02:37:22 UTC (rev 2334)
@@ -11,22 +11,11 @@
  */
 package com.thoughtworks.xstream.converters.reflection;
 
-import com.thoughtworks.xstream.converters.ConversionException;
-import com.thoughtworks.xstream.core.Caching;
-import com.thoughtworks.xstream.core.util.FastField;
-
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
-import java.io.ObjectStreamField;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
 
+import com.thoughtworks.xstream.core.Caching;
+import com.thoughtworks.xstream.core.util.SerializationMembers;
 
 /**
  * Convenience wrapper to invoke special serialization methods on objects (and perform
@@ -34,211 +23,60 @@
  *
  * @author Joe Walnes
  * @author Jörg Schaible
+ * @deprecated As of upcoming, moved into internal util package.
  */
 public class SerializationMethodInvoker implements Caching {
 
-    private static final Method NO_METHOD = (new Object() {
-        private void noMethod() {
-        }
-    }).getClass().getDeclaredMethods()[0];
-    private static final Object[] EMPTY_ARGS = new Object[0];
-    private static final Class[] EMPTY_CLASSES = new Class[0];
-    private static final Map NO_FIELDS = Collections.EMPTY_MAP;
-    private static final int PERSISTENT_FIELDS_MODIFIER = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
-    private static final FastField[] OBJECT_TYPE_FIELDS = {
-        new FastField(Object.class, "readResolve"), 
-        new FastField(Object.class, "writeReplace"), 
-        new FastField(Object.class, "readObject"), 
-        new FastField(Object.class, "writeObject")
-    };
-    private Map declaredCache = Collections.synchronizedMap(new HashMap());
-    private Map resRepCache = Collections.synchronizedMap(new HashMap());
-    private final Map fieldCache = Collections.synchronizedMap(new HashMap());
-    {
-        for(int i = 0; i < OBJECT_TYPE_FIELDS.length; ++i) {
-            declaredCache.put(OBJECT_TYPE_FIELDS[i], NO_METHOD);
-        }
-        for(int i = 0; i < 2; ++i) {
-            resRepCache.put(OBJECT_TYPE_FIELDS[i], NO_METHOD);
-        }
-    }
+    SerializationMembers serializationMembers = new SerializationMembers();
 
     /**
      * Resolves an object as native serialization does by calling readResolve(), if available.
+     * 
+     * @deprecated As of upcoming, moved into internal util package.
      */
     public Object callReadResolve(Object result) {
-        if (result == null) {
-            return null;
-        } else {
-            final Class resultType = result.getClass();
-            final Method readResolveMethod = getRRMethod(resultType, "readResolve");
-            if (readResolveMethod != null) {
-                try {
-                    return readResolveMethod.invoke(result, EMPTY_ARGS);
-                } catch (IllegalAccessException e) {
-                    throw new ObjectAccessException("Could not call "
-                        + resultType.getName()
-                        + ".readResolve()", e);
-                } catch (InvocationTargetException e) {
-                    throw new ObjectAccessException("Could not call "
-                        + resultType.getName()
-                        + ".readResolve()", e.getTargetException());
-                }
-            } else {
-                return result;
-            }
-        }
+        return serializationMembers.callReadResolve(result);
     }
 
+    /**
+     * @deprecated As of upcoming, moved into internal util package.
+     */
     public Object callWriteReplace(Object object) {
-        if (object == null) {
-            return null;
-        } else {
-            final Class objectType = object.getClass();
-            final Method writeReplaceMethod = getRRMethod(objectType, "writeReplace");
-            if (writeReplaceMethod != null) {
-                try {
-                    return writeReplaceMethod.invoke(object, EMPTY_ARGS);
-                } catch (IllegalAccessException e) {
-                    throw new ObjectAccessException("Could not call "
-                        + objectType.getName()
-                        + ".writeReplace()", e);
-                } catch (InvocationTargetException e) {
-                    throw new ObjectAccessException("Could not call "
-                        + objectType.getName()
-                        + ".writeReplace()", e.getTargetException());
-                }
-            } else {
-                return object;
-            }
-        }
+        return serializationMembers.callWriteReplace(object);
     }
 
+    /**
+     * @deprecated As of upcoming, moved into internal util package.
+     */
     public boolean supportsReadObject(Class type, boolean includeBaseClasses) {
-        return getMethod(
-            type, "readObject", new Class[]{ObjectInputStream.class}, includeBaseClasses) != null;
+        return serializationMembers.supportsReadObject(type, includeBaseClasses);
     }
 
+    /**
+     * @deprecated As of upcoming, moved into internal util package.
+     */
     public void callReadObject(Class type, Object object, ObjectInputStream stream) {
-        try {
-            Method readObjectMethod = getMethod(
-                type, "readObject", new Class[]{ObjectInputStream.class}, false);
-            readObjectMethod.invoke(object, new Object[]{stream});
-        } catch (IllegalAccessException e) {
-            throw new ConversionException("Could not call "
-                + object.getClass().getName()
-                + ".readObject()", e);
-        } catch (InvocationTargetException e) {
-            throw new ConversionException("Could not call "
-                + object.getClass().getName()
-                + ".readObject()", e.getTargetException());
-        }
+        serializationMembers.callReadObject(type, object, stream);
     }
 
+    /**
+     * @deprecated As of upcoming, moved into internal util package.
+     */
     public boolean supportsWriteObject(Class type, boolean includeBaseClasses) {
-        return getMethod(
-            type, "writeObject", new Class[]{ObjectOutputStream.class}, includeBaseClasses) != null;
+        return serializationMembers.supportsWriteObject(type, includeBaseClasses);
     }
 
+    /**
+     * @deprecated As of upcoming, moved into internal util package.
+     */
     public void callWriteObject(Class type, Object instance, ObjectOutputStream stream) {
-        try {
-            Method readObjectMethod = getMethod(
-                type, "writeObject", new Class[]{ObjectOutputStream.class}, false);
-            readObjectMethod.invoke(instance, new Object[]{stream});
-        } catch (IllegalAccessException e) {
-            throw new ConversionException("Could not call "
-                + instance.getClass().getName()
-                + ".writeObject()", e);
-        } catch (InvocationTargetException e) {
-            throw new ConversionException("Could not call "
-                + instance.getClass().getName()
-                + ".writeObject()", e.getTargetException());
-        }
+        serializationMembers.callWriteObject(type, instance, stream);
     }
 
-    private Method getMethod(Class type, String name, Class[] parameterTypes,
-        boolean includeBaseclasses) {
-        Method method = getMethod(type, name, parameterTypes);
-        return method == NO_METHOD
-            || (!includeBaseclasses && !method.getDeclaringClass().equals(type))
-            ? null
-            : method;
-    }
-
-    private Method getMethod(Class type, String name, Class[] parameterTypes) {
-        if (type == null) {
-            return null;
-        }
-        FastField method = new FastField(type, name);
-        Method result = (Method)declaredCache.get(method);
-        if (result == null) {
-            try {
-                result = type.getDeclaredMethod(name, parameterTypes);
-                if (!result.isAccessible()) {
-                    result.setAccessible(true);
-                }
-            } catch (NoSuchMethodException e) {
-                result = getMethod(type.getSuperclass(), name, parameterTypes);
-            }
-            declaredCache.put(method, result);
-        }
-        return result;
-    }
-
-    private Method getRRMethod(final Class type, final String name) {
-        final FastField method = new FastField(type, name);
-        Method result = (Method)resRepCache.get(method);
-        if (result == null) {
-            result = getMethod(type, name, EMPTY_CLASSES, true);
-            if (result != null && result.getDeclaringClass() != type) {
-                if ((result.getModifiers() & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0) {
-                    if ((result.getModifiers() & Modifier.PRIVATE) > 0
-                            || type.getPackage() != result.getDeclaringClass().getPackage()) {
-                        result = NO_METHOD;
-                    }
-                }
-            } else if (result == null) {
-                result = NO_METHOD;
-            }
-            resRepCache.put(method, result);
-        }
-        return result == NO_METHOD ? null : result;
-    }
-
-    public Map getSerializablePersistentFields(final Class type) {
-        if (type == null) {
-            return null;
-        }
-        Map result = (Map)fieldCache.get(type.getName());
-        if (result == null) {
-            try {
-                final Field field = type.getDeclaredField("serialPersistentFields");
-                if ((field.getModifiers() & PERSISTENT_FIELDS_MODIFIER) == PERSISTENT_FIELDS_MODIFIER) {
-                    field.setAccessible(true);
-                    final ObjectStreamField[] fields = (ObjectStreamField[])field.get(null);
-                    if (fields != null) {
-                        result = new HashMap();
-                        for (int i = 0; i < fields.length; ++i) {
-                            result.put(fields[i].getName(), fields[i]);
-                        }
-                    }
-                }
-            } catch (final NoSuchFieldException e) {
-            } catch (final IllegalAccessException e) {
-                throw new ObjectAccessException("Cannot get " + type.getName() + ".serialPersistentFields.", e);
-            } catch (final ClassCastException e) {
-                throw new ObjectAccessException("Cannot get " + type.getName() + ".serialPersistentFields.", e);
-            }
-            if (result == null) {
-                result = NO_FIELDS;
-            }
-            fieldCache.put(type.getName(), result);
-        }
-        return result == NO_FIELDS ? null : result;
-    }
-
+    /**
+     * @deprecated As of upcoming, moved into internal util package.
+     */
     public void flushCache() {
-        declaredCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS));
-        resRepCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS));
+        serializationMembers.flushCache();
     }
 }

Copied: branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/core/util/SerializationMembers.java (from rev 2333, trunk/xstream/src/java/com/thoughtworks/xstream/core/util/SerializationMembers.java) (0 => 2334)


--- branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/core/util/SerializationMembers.java	                        (rev 0)
+++ branches/v-1.4.x/xstream/src/java/com/thoughtworks/xstream/core/util/SerializationMembers.java	2015-02-15 02:37:22 UTC (rev 2334)
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2004, 2005 Joe Walnes.
+ * Copyright (C) 2006, 2007, 2008, 2010, 2011, 2014, 2015 XStream Committers.
+ * All rights reserved.
+ *
+ * The software in this package is published under the terms of the BSD
+ * style license a copy of which has been included with this distribution in
+ * the LICENSE.txt file.
+ *
+ * Created on 12. February 2015 by Joerg Schaible, copied from c.t.x.converters.reflection.SerializationMemberInvoker.
+ */
+package com.thoughtworks.xstream.core.util;
+
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import com.thoughtworks.xstream.converters.ConversionException;
+import com.thoughtworks.xstream.converters.reflection.ObjectAccessException;
+import com.thoughtworks.xstream.core.Caching;
+
+
+/**
+ * Convenience wrapper to invoke special serialization methods on objects (and perform reflection caching).
+ *
+ * @author Joe Walnes
+ * @author J&ouml;rg Schaible
+ */
+public class SerializationMembers implements Caching {
+
+    private static final Method NO_METHOD = (new Object() {
+        private void noMethod() {
+        }
+    }).getClass().getDeclaredMethods()[0];
+    private static final Object[] EMPTY_ARGS = new Object[0];
+    private static final Class[] EMPTY_CLASSES = new Class[0];
+    private static final Map NO_FIELDS = Collections.EMPTY_MAP;
+    private static final int PERSISTENT_FIELDS_MODIFIER = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
+    private static final FastField[] OBJECT_TYPE_FIELDS = {
+        new FastField(Object.class, "readResolve"), 
+        new FastField(Object.class, "writeReplace"), 
+        new FastField(Object.class, "readObject"), 
+        new FastField(Object.class, "writeObject")
+    };
+    private Map declaredCache = Collections.synchronizedMap(new HashMap());
+    private Map resRepCache = Collections.synchronizedMap(new HashMap());
+    private final Map fieldCache = Collections.synchronizedMap(new HashMap());
+    {
+        for(int i = 0; i < OBJECT_TYPE_FIELDS.length; ++i) {
+            declaredCache.put(OBJECT_TYPE_FIELDS[i], NO_METHOD);
+        }
+        for(int i = 0; i < 2; ++i) {
+            resRepCache.put(OBJECT_TYPE_FIELDS[i], NO_METHOD);
+        }
+    }
+
+    /**
+     * Resolves an object as native serialization does by calling readResolve(), if available.
+     */
+    public Object callReadResolve(final Object result) {
+        if (result == null) {
+            return null;
+        } else {
+            final Class resultType = result.getClass();
+            final Method readResolveMethod = getRRMethod(resultType, "readResolve");
+            if (readResolveMethod != null) {
+                try {
+                    return readResolveMethod.invoke(result, EMPTY_ARGS);
+                } catch (IllegalAccessException e) {
+                    throw new ObjectAccessException("Could not call "
+                        + resultType.getName()
+                        + ".readResolve()", e);
+                } catch (InvocationTargetException e) {
+                    throw new ObjectAccessException("Could not call "
+                        + resultType.getName()
+                        + ".readResolve()", e.getTargetException());
+                }
+            } else {
+                return result;
+            }
+        }
+    }
+
+    public Object callWriteReplace(final Object object) {
+        if (object == null) {
+            return null;
+        } else {
+            final Class objectType = object.getClass();
+            final Method writeReplaceMethod = getRRMethod(objectType, "writeReplace");
+            if (writeReplaceMethod != null) {
+                try {
+                    return writeReplaceMethod.invoke(object, EMPTY_ARGS);
+                } catch (IllegalAccessException e) {
+                    throw new ObjectAccessException("Could not call "
+                        + objectType.getName()
+                        + ".writeReplace()", e);
+                } catch (InvocationTargetException e) {
+                    throw new ObjectAccessException("Could not call "
+                        + objectType.getName()
+                        + ".writeReplace()", e.getTargetException());
+                }
+            } else {
+                return object;
+            }
+        }
+    }
+
+    public boolean supportsReadObject(final Class type, final boolean includeBaseClasses) {
+        return getMethod(
+            type, "readObject", new Class[]{ObjectInputStream.class}, includeBaseClasses) != null;
+    }
+
+    public void callReadObject(final Class type, final Object object, final ObjectInputStream stream) {
+        try {
+            Method readObjectMethod = getMethod(
+                type, "readObject", new Class[]{ObjectInputStream.class}, false);
+            readObjectMethod.invoke(object, new Object[]{stream});
+        } catch (IllegalAccessException e) {
+            throw new ConversionException("Could not call "
+                + object.getClass().getName()
+                + ".readObject()", e);
+        } catch (InvocationTargetException e) {
+            throw new ConversionException("Could not call "
+                + object.getClass().getName()
+                + ".readObject()", e.getTargetException());
+        }
+    }
+
+    public boolean supportsWriteObject(final Class type, final boolean includeBaseClasses) {
+        return getMethod(
+            type, "writeObject", new Class[]{ObjectOutputStream.class}, includeBaseClasses) != null;
+    }
+
+    public void callWriteObject(final Class type, final Object instance, final ObjectOutputStream stream) {
+        try {
+            Method readObjectMethod = getMethod(
+                type, "writeObject", new Class[]{ObjectOutputStream.class}, false);
+            readObjectMethod.invoke(instance, new Object[]{stream});
+        } catch (IllegalAccessException e) {
+            throw new ConversionException("Could not call "
+                + instance.getClass().getName()
+                + ".writeObject()", e);
+        } catch (InvocationTargetException e) {
+            throw new ConversionException("Could not call "
+                + instance.getClass().getName()
+                + ".writeObject()", e.getTargetException());
+        }
+    }
+
+    private Method getMethod(Class type, String name, Class[] parameterTypes,
+            boolean includeBaseclasses) {
+            Method method = getMethod(type, name, parameterTypes);
+            return method == NO_METHOD
+                || (!includeBaseclasses && !method.getDeclaringClass().equals(type))
+                ? null
+                : method;
+        }
+
+        private Method getMethod(Class type, String name, Class[] parameterTypes) {
+            if (type == null) {
+                return null;
+            }
+            FastField method = new FastField(type, name);
+            Method result = (Method)declaredCache.get(method);
+            if (result == null) {
+                try {
+                    result = type.getDeclaredMethod(name, parameterTypes);
+                    if (!result.isAccessible()) {
+                        result.setAccessible(true);
+                    }
+                } catch (NoSuchMethodException e) {
+                    result = getMethod(type.getSuperclass(), name, parameterTypes);
+                }
+                declaredCache.put(method, result);
+            }
+            return result;
+        }
+
+        private Method getRRMethod(final Class type, final String name) {
+            final FastField method = new FastField(type, name);
+            Method result = (Method)resRepCache.get(method);
+            if (result == null) {
+                result = getMethod(type, name, EMPTY_CLASSES, true);
+                if (result != null && result.getDeclaringClass() != type) {
+                    if ((result.getModifiers() & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0) {
+                        if ((result.getModifiers() & Modifier.PRIVATE) > 0
+                                || type.getPackage() != result.getDeclaringClass().getPackage()) {
+                            result = NO_METHOD;
+                        }
+                    }
+                } else if (result == null) {
+                    result = NO_METHOD;
+                }
+                resRepCache.put(method, result);
+            }
+            return result == NO_METHOD ? null : result;
+        }
+
+        public Map getSerializablePersistentFields(final Class type) {
+            if (type == null) {
+                return null;
+            }
+            Map result = (Map)fieldCache.get(type.getName());
+            if (result == null) {
+                try {
+                    final Field field = type.getDeclaredField("serialPersistentFields");
+                    if ((field.getModifiers() & PERSISTENT_FIELDS_MODIFIER) == PERSISTENT_FIELDS_MODIFIER) {
+                        field.setAccessible(true);
+                        final ObjectStreamField[] fields = (ObjectStreamField[])field.get(null);
+                        if (fields != null) {
+                            result = new HashMap();
+                            for (int i = 0; i < fields.length; ++i) {
+                                result.put(fields[i].getName(), fields[i]);
+                            }
+                        }
+                    }
+                } catch (final NoSuchFieldException e) {
+                } catch (final IllegalAccessException e) {
+                    throw new ObjectAccessException("Cannot get " + type.getName() + ".serialPersistentFields.", e);
+                } catch (final ClassCastException e) {
+                    throw new ObjectAccessException("Cannot get " + type.getName() + ".serialPersistentFields.", e);
+                }
+                if (result == null) {
+                    result = NO_FIELDS;
+                }
+                fieldCache.put(type.getName(), result);
+            }
+            return result == NO_FIELDS ? null : result;
+        }
+
+    public void flushCache() {
+        declaredCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS));
+        resRepCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS));
+    }
+}

Modified: branches/v-1.4.x/xstream-distribution/src/content/changes.html (2333 => 2334)


--- branches/v-1.4.x/xstream-distribution/src/content/changes.html	2015-02-14 16:44:43 UTC (rev 2333)
+++ branches/v-1.4.x/xstream-distribution/src/content/changes.html	2015-02-15 02:37:22 UTC (rev 2334)
@@ -61,6 +61,7 @@
     	<li>c.t.x.converters.reflection.AbstractReflectionConverter.readResolve() is protected now.</li>
     	<li>c.t.x.mapper.AbstractAttributeAliasingMapper.readResolve() is protected now.</li>
     	<li>Deprecated c.t.x.converters.extended.StackTraceElementFactory, it is an internal helper class.</li>
+    	<li>Deprecated c.t.x.converters.reflection.SerializationMethodInvoker, it is an internal helper class.</li>
     	<li>Deprecated c.t.x.io.AttributeNameIterator, it is an internal helper class.</li>
     	<li>Deprecated c.t.x.XStream.useXStream11XmlFriendlyMapper(), corresponding
     	c.t.x.mapper.XStream11XmlFriendlyMapper has been deprecated long ago.</li>

To unsubscribe from this list please visit:

http://xircles.codehaus.org/manage_email

Reply via email to