Title: [2333] trunk: Move SerializationMethodInvoker into core.util and renamed it to SerializationMembers.

Diff

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java (2332 => 2333)


--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java	2015-02-12 23:11:00 UTC (rev 2332)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.java	2015-02-14 16:44:43 UTC (rev 2333)
@@ -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
@@ -36,6 +36,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(final Mapper mapper, final ReflectionProvider reflectionProvider) {
         this.mapper = mapper;
         this.reflectionProvider = reflectionProvider;
         serializationMethodInvoker = new SerializationMethodInvoker();
+        serializationMembers = serializationMethodInvoker.serializationMembers;
     }
 
     protected boolean canAccess(final Class<?> type) {
@@ -68,7 +75,7 @@
 
     @Override
     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);
@@ -242,7 +249,7 @@
     public Object unmarshal(final HierarchicalStreamReader reader, 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,
@@ -534,6 +541,7 @@
 
     protected Object readResolve() {
         serializationMethodInvoker = new SerializationMethodInvoker();
+        serializationMembers = serializationMethodInvoker.serializationMembers;
         return this;
     }
 

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java (2332 => 2333)


--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java	2015-02-12 23:11:00 UTC (rev 2332)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/CGLIBEnhancedConverter.java	2015-02-14 16:44:43 UTC (rev 2333)
@@ -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
@@ -405,7 +405,7 @@
         if (result == null) {
             result = create(enhancer, callbacks, useFactory);
         }
-        return serializationMethodInvoker.callReadResolve(result);
+        return serializationMembers.callReadResolve(result);
     }
 
     private void readCallback(final HierarchicalStreamReader reader, final UnmarshallingContext context,

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java (2332 => 2333)


--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java	2015-02-12 23:11:00 UTC (rev 2332)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/ExternalizableConverter.java	2015-02-14 16:44:43 UTC (rev 2333)
@@ -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
@@ -29,6 +29,7 @@
 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;
@@ -45,7 +46,7 @@
 
     private final Mapper mapper;
     private final ClassLoaderReference classLoaderReference;
-    private transient SerializationMethodInvoker serializationMethodInvoker;
+    private transient SerializationMembers serializationMembers;
 
     /**
      * Construct an ExternalizableConverter.
@@ -57,7 +58,7 @@
     public ExternalizableConverter(final Mapper mapper, final ClassLoaderReference classLoaderReference) {
         this.mapper = mapper;
         this.classLoaderReference = classLoaderReference;
-        serializationMethodInvoker = new SerializationMethodInvoker();
+        serializationMembers = new SerializationMembers();
     }
 
     /**
@@ -83,7 +84,7 @@
 
     @Override
     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);
         }
@@ -192,7 +193,7 @@
                 externalizable.readExternal(objectInput);
                 objectInput.popCallback();
             }
-            return serializationMethodInvoker.callReadResolve(externalizable);
+            return serializationMembers.callReadResolve(externalizable);
         } catch (final NoSuchMethodException e) {
             throw new ConversionException("Cannot construct " + type.getClass() + ", missing default constructor", e);
         } catch (final InvocationTargetException e) {
@@ -209,7 +210,7 @@
     }
 
     private Object readResolve() {
-        serializationMethodInvoker = new SerializationMethodInvoker();
+        serializationMembers = new SerializationMembers();
         return this;
     }
 }

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java (2332 => 2333)


--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java	2015-02-12 23:11:00 UTC (rev 2332)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializableConverter.java	2015-02-14 16:44:43 UTC (rev 2333)
@@ -111,7 +111,7 @@
         if (type != null
             && Serializable.class.isAssignableFrom(type)
             && !type.isInterface()
-            && (serializationMethodInvoker.supportsReadObject(type, true) || serializationMethodInvoker
+            && (serializationMembers.supportsReadObject(type, true) || serializationMembers
                 .supportsWriteObject(type, true))) {
             for (final Class<?> clazz : hierarchyFor(type)) {
                 if (!Serializable.class.isAssignableFrom(clazz)) {
@@ -257,7 +257,7 @@
                         marshalUnserializableParent(writer, context, source);
                         mustHandleUnserializableParent = false;
                     }
-                    if (serializationMethodInvoker.supportsWriteObject(currentType, false)) {
+                    if (serializationMembers.supportsWriteObject(currentType, false)) {
                         writtenClassWrapper[0] = true;
                         writer.startNode(mapper.serializedClass(currentType));
                         if (currentType != mapper.defaultImplementationOf(currentType)) {
@@ -269,10 +269,10 @@
                         @SuppressWarnings("resource")
                         final CustomObjectOutputStream objectOutputStream = CustomObjectOutputStream.getInstance(
                             context, callback);
-                        serializationMethodInvoker.callWriteObject(currentType, source, objectOutputStream);
+                        serializationMembers.callWriteObject(currentType, source, objectOutputStream);
                         objectOutputStream.popCallback();
                         writer.endNode();
-                    } else if (serializationMethodInvoker.supportsReadObject(currentType, false)) {
+                    } else if (serializationMembers.supportsReadObject(currentType, 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.
@@ -416,7 +416,7 @@
 
             @Override
             public void defaultReadObject() {
-                if (serializationMethodInvoker.getSerializablePersistentFields(currentType[0]) != null) {
+                if (serializationMembers.getSerializablePersistentFields(currentType[0]) != null) {
                     readFieldsFromStream();
                     return;
                 }
@@ -483,11 +483,11 @@
                 } else {
                     currentType[0] = mapper.realClass(classAttribute);
                 }
-                if (serializationMethodInvoker.supportsReadObject(currentType[0], false)) {
+                if (serializationMembers.supportsReadObject(currentType[0], false)) {
                     @SuppressWarnings("resource")
                     final CustomObjectInputStream objectInputStream = CustomObjectInputStream.getInstance(context,
                         callback, classLoaderReference);
-                    serializationMethodInvoker.callReadObject(currentType[0], result, objectInputStream);
+                    serializationMembers.callReadObject(currentType[0], result, objectInputStream);
                     objectInputStream.popCallback();
                 } else {
                     try {

Modified: trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java (2332 => 2333)


--- trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java	2015-02-12 23:11:00 UTC (rev 2332)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java	2015-02-14 16:44:43 UTC (rev 2333)
@@ -13,21 +13,9 @@
 
 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.core.Caching;
-import com.thoughtworks.xstream.core.util.FastField;
+import com.thoughtworks.xstream.core.util.SerializationMembers;
 
 
 /**
@@ -35,190 +23,69 @@
  *
  * @author Joe Walnes
  * @author J&ouml;rg Schaible
+ * @deprecated As of upcoming, moved into internal util package.
  */
+@Deprecated
 public class SerializationMethodInvoker implements Caching {
 
-    private static final Method NO_METHOD = new Object() {
-        @SuppressWarnings("unused")
-        private void noMethod() {
-        }
-    }.getClass().getDeclaredMethods()[0];
-    private static final Map<String, ObjectStreamField> NO_FIELDS = Collections.emptyMap();
-    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 final ConcurrentMap<FastField, Method> declaredCache = new ConcurrentHashMap<FastField, Method>();
-    private final ConcurrentMap<FastField, Method> resRepCache = new ConcurrentHashMap<FastField, Method>();
-    private final ConcurrentMap<String, Map<String, ObjectStreamField>> fieldCache = new ConcurrentHashMap<String, Map<String, ObjectStreamField>>();
-    {
-        for (final FastField element : OBJECT_TYPE_FIELDS) {
-            declaredCache.put(element, NO_METHOD);
-        }
-        for (final FastField element : Arrays.copyOf(OBJECT_TYPE_FIELDS, 2)) {
-            resRepCache.put(element, 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.
      */
+    @Deprecated
     public Object callReadResolve(final Object result) {
-        if (result == null) {
-            return null;
-        } else {
-            final Class<? extends Object> resultType = result.getClass();
-            final Method readResolveMethod = getRRMethod(resultType, "readResolve");
-            if (readResolveMethod != null) {
-                try {
-                    return readResolveMethod.invoke(result);
-                } catch (final IllegalAccessException e) {
-                    throw new ObjectAccessException("Could not call " + resultType.getName() + ".readResolve()", e);
-                } catch (final 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.
+     */
+    @Deprecated
     public Object callWriteReplace(final Object object) {
-        if (object == null) {
-            return null;
-        } else {
-            final Class<? extends Object> objectType = object.getClass();
-            final Method writeReplaceMethod = getRRMethod(objectType, "writeReplace");
-            if (writeReplaceMethod != null) {
-                try {
-                    return writeReplaceMethod.invoke(object);
-                } catch (final IllegalAccessException e) {
-                    throw new ObjectAccessException("Could not call " + objectType.getName() + ".writeReplace()", e);
-                } catch (final 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.
+     */
+    @Deprecated
     public boolean supportsReadObject(final Class<?> type, final boolean includeBaseClasses) {
-        return getMethod(type, "readObject", includeBaseClasses, ObjectInputStream.class) != null;
+        return serializationMembers.supportsReadObject(type, includeBaseClasses);
     }
 
+    /**
+     * @deprecated As of upcoming, moved into internal util package.
+     */
+    @Deprecated
     public void callReadObject(final Class<?> type, final Object object, final ObjectInputStream stream) {
-        try {
-            final Method readObjectMethod = getMethod(type, "readObject", false, ObjectInputStream.class);
-            readObjectMethod.invoke(object, stream);
-        } catch (final IllegalAccessException e) {
-            throw new ConversionException("Could not call " + object.getClass().getName() + ".readObject()", e);
-        } catch (final 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.
+     */
+    @Deprecated
     public boolean supportsWriteObject(final Class<?> type, final boolean includeBaseClasses) {
-        return getMethod(type, "writeObject", includeBaseClasses, ObjectOutputStream.class) != null;
+        return serializationMembers.supportsWriteObject(type, includeBaseClasses);
     }
 
+    /**
+     * @deprecated As of upcoming, moved into internal util package.
+     */
+    @Deprecated
     public void callWriteObject(final Class<?> type, final Object instance, final ObjectOutputStream stream) {
-        try {
-            final Method readObjectMethod = getMethod(type, "writeObject", false, ObjectOutputStream.class);
-            readObjectMethod.invoke(instance, stream);
-        } catch (final IllegalAccessException e) {
-            throw new ConversionException("Could not call " + instance.getClass().getName() + ".writeObject()", e);
-        } catch (final InvocationTargetException e) {
-            throw new ConversionException("Could not call " + instance.getClass().getName() + ".writeObject()", e
-                .getTargetException());
-        }
+        serializationMembers.callWriteObject(type, instance, stream);
     }
 
-    private Method getMethod(final Class<?> type, final String name, final boolean includeBaseclasses,
-            final Class<?>... parameterTypes) {
-        final Method method = getMethod(type, name, parameterTypes);
-        return method == NO_METHOD || !includeBaseclasses && !method.getDeclaringClass().equals(type) ? null : method;
-    }
-
-    private Method getMethod(final Class<?> type, final String name, final Class<?>... parameterTypes) {
-        if (type == null) {
-            return null;
-        }
-        final FastField method = new FastField(type, name);
-        Method result = declaredCache.get(method);
-
-        if (result == null) {
-            try {
-                result = type.getDeclaredMethod(name, parameterTypes);
-                if (!result.isAccessible()) {
-                    result.setAccessible(true);
-                }
-            } catch (final 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 = resRepCache.get(method);
-        if (result == null) {
-            result = getMethod(type, name, 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.putIfAbsent(method, result);
-        }
-        return result == NO_METHOD ? null : result;
-    }
-
-    public Map<String, ObjectStreamField> getSerializablePersistentFields(final Class<?> type) {
-        if (type == null) {
-            return null;
-        }
-        Map<String, ObjectStreamField> result = 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<String, ObjectStreamField>();
-                        for (final ObjectStreamField f : fields) {
-                            result.put(f.getName(), f);
-                        }
-                    }
-                }
-            } 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.putIfAbsent(type.getName(), result);
-        }
-        return result == NO_FIELDS ? null : result;
-    }
-
+    /**
+     * @deprecated As of upcoming, moved into internal util package.
+     */
     @Override
+    @Deprecated
     public void flushCache() {
-        declaredCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS));
-        resRepCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS));
+        serializationMembers.flushCache();
     }
 }

Copied: trunk/xstream/src/java/com/thoughtworks/xstream/core/util/SerializationMembers.java (from rev 2329, trunk/xstream/src/java/com/thoughtworks/xstream/converters/reflection/SerializationMethodInvoker.java) (0 => 2333)


--- trunk/xstream/src/java/com/thoughtworks/xstream/core/util/SerializationMembers.java	                        (rev 0)
+++ trunk/xstream/src/java/com/thoughtworks/xstream/core/util/SerializationMembers.java	2015-02-14 16:44:43 UTC (rev 2333)
@@ -0,0 +1,224 @@
+/*
+ * 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() {
+        @SuppressWarnings("unused")
+        private void noMethod() {
+        }
+    }.getClass().getDeclaredMethods()[0];
+    private static final Map<String, ObjectStreamField> NO_FIELDS = Collections.emptyMap();
+    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 final ConcurrentMap<FastField, Method> declaredCache = new ConcurrentHashMap<FastField, Method>();
+    private final ConcurrentMap<FastField, Method> resRepCache = new ConcurrentHashMap<FastField, Method>();
+    private final ConcurrentMap<String, Map<String, ObjectStreamField>> fieldCache = new ConcurrentHashMap<String, Map<String, ObjectStreamField>>();
+    {
+        for (final FastField element : OBJECT_TYPE_FIELDS) {
+            declaredCache.put(element, NO_METHOD);
+        }
+        for (final FastField element : Arrays.copyOf(OBJECT_TYPE_FIELDS, 2)) {
+            resRepCache.put(element, 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<? extends Object> resultType = result.getClass();
+            final Method readResolveMethod = getRRMethod(resultType, "readResolve");
+            if (readResolveMethod != null) {
+                try {
+                    return readResolveMethod.invoke(result);
+                } catch (final IllegalAccessException e) {
+                    throw new ObjectAccessException("Could not call " + resultType.getName() + ".readResolve()", e);
+                } catch (final 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<? extends Object> objectType = object.getClass();
+            final Method writeReplaceMethod = getRRMethod(objectType, "writeReplace");
+            if (writeReplaceMethod != null) {
+                try {
+                    return writeReplaceMethod.invoke(object);
+                } catch (final IllegalAccessException e) {
+                    throw new ObjectAccessException("Could not call " + objectType.getName() + ".writeReplace()", e);
+                } catch (final 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", includeBaseClasses, ObjectInputStream.class) != null;
+    }
+
+    public void callReadObject(final Class<?> type, final Object object, final ObjectInputStream stream) {
+        try {
+            final Method readObjectMethod = getMethod(type, "readObject", false, ObjectInputStream.class);
+            readObjectMethod.invoke(object, stream);
+        } catch (final IllegalAccessException e) {
+            throw new ConversionException("Could not call " + object.getClass().getName() + ".readObject()", e);
+        } catch (final 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", includeBaseClasses, ObjectOutputStream.class) != null;
+    }
+
+    public void callWriteObject(final Class<?> type, final Object instance, final ObjectOutputStream stream) {
+        try {
+            final Method readObjectMethod = getMethod(type, "writeObject", false, ObjectOutputStream.class);
+            readObjectMethod.invoke(instance, stream);
+        } catch (final IllegalAccessException e) {
+            throw new ConversionException("Could not call " + instance.getClass().getName() + ".writeObject()", e);
+        } catch (final InvocationTargetException e) {
+            throw new ConversionException("Could not call " + instance.getClass().getName() + ".writeObject()", e
+                .getTargetException());
+        }
+    }
+
+    private Method getMethod(final Class<?> type, final String name, final boolean includeBaseclasses,
+            final Class<?>... parameterTypes) {
+        final Method method = getMethod(type, name, parameterTypes);
+        return method == NO_METHOD || !includeBaseclasses && !method.getDeclaringClass().equals(type) ? null : method;
+    }
+
+    private Method getMethod(final Class<?> type, final String name, final Class<?>... parameterTypes) {
+        if (type == null) {
+            return null;
+        }
+        final FastField method = new FastField(type, name);
+        Method result = declaredCache.get(method);
+
+        if (result == null) {
+            try {
+                result = type.getDeclaredMethod(name, parameterTypes);
+                if (!result.isAccessible()) {
+                    result.setAccessible(true);
+                }
+            } catch (final 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 = resRepCache.get(method);
+        if (result == null) {
+            result = getMethod(type, name, 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.putIfAbsent(method, result);
+        }
+        return result == NO_METHOD ? null : result;
+    }
+
+    public Map<String, ObjectStreamField> getSerializablePersistentFields(final Class<?> type) {
+        if (type == null) {
+            return null;
+        }
+        Map<String, ObjectStreamField> result = 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<String, ObjectStreamField>();
+                        for (final ObjectStreamField f : fields) {
+                            result.put(f.getName(), f);
+                        }
+                    }
+                }
+            } 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.putIfAbsent(type.getName(), result);
+        }
+        return result == NO_FIELDS ? null : result;
+    }
+
+    @Override
+    public void flushCache() {
+        declaredCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS));
+        resRepCache.keySet().retainAll(Arrays.asList(OBJECT_TYPE_FIELDS));
+    }
+}

Modified: trunk/xstream-distribution/src/content/changes.html (2332 => 2333)


--- trunk/xstream-distribution/src/content/changes.html	2015-02-12 23:11:00 UTC (rev 2332)
+++ trunk/xstream-distribution/src/content/changes.html	2015-02-14 16:44:43 UTC (rev 2333)
@@ -86,6 +86,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