com.feilong.lib.xstream.core.util.SerializationMembers Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of feilong Show documentation
Show all versions of feilong Show documentation
feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.
/*
* Copyright (C) 2004, 2005 Joe Walnes.
* Copyright (C) 2006, 2007, 2008, 2010, 2011, 2014, 2015, 2016 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.feilong.lib.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 com.feilong.lib.xstream.converters.ConversionException;
import com.feilong.lib.xstream.converters.ErrorWritingException;
import com.feilong.lib.xstream.converters.reflection.ObjectAccessException;
import com.feilong.lib.xstream.core.Caching;
/**
* Convenience wrapper to invoke special serialization methods on objects (and perform reflection caching).
*
* @author Joe Walnes
* @author Jö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 (FastField element : OBJECT_TYPE_FIELDS){
declaredCache.put(element, 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){
ErrorWritingException ex = null;
try{
return readResolveMethod.invoke(result, EMPTY_ARGS);
}catch (IllegalAccessException e){
ex = new ObjectAccessException("Cannot access method", e);
}catch (InvocationTargetException e){
ex = new ConversionException("Failed calling method", e.getTargetException());
}
ex.add("method", resultType.getName() + ".readResolve()");
throw ex;
}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){
ErrorWritingException ex = null;
try{
Object replaced = writeReplaceMethod.invoke(object, EMPTY_ARGS);
if (replaced != null && !object.getClass().equals(replaced.getClass())){
// call further writeReplace methods on replaced
replaced = callWriteReplace(replaced);
}
return replaced;
}catch (final IllegalAccessException e){
ex = new ObjectAccessException("Cannot access method", e);
}catch (InvocationTargetException e){
ex = new ConversionException("Failed calling method", e.getTargetException());
}catch (final ErrorWritingException e){
ex = e;
}
ex.add("method", objectType.getName() + ".writeReplace()");
throw ex;
}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){
ErrorWritingException ex = null;
try{
Method readObjectMethod = getMethod(type, "readObject", new Class[] { ObjectInputStream.class }, false);
readObjectMethod.invoke(object, new Object[] { stream });
}catch (IllegalAccessException e){
ex = new ObjectAccessException("Cannot access method", e);
}catch (InvocationTargetException e){
ex = new ConversionException("Failed calling method", e.getTargetException());
}
if (ex != null){
ex.add("method", object.getClass().getName() + ".readObject()");
throw ex;
}
}
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){
ErrorWritingException ex = null;
try{
Method readObjectMethod = getMethod(type, "writeObject", new Class[] { ObjectOutputStream.class }, false);
readObjectMethod.invoke(instance, new Object[] { stream });
}catch (IllegalAccessException e){
ex = new ObjectAccessException("Cannot access method", e);
}catch (InvocationTargetException e){
ex = new ConversionException("Failed calling method", e.getTargetException());
}
if (ex != null){
ex.add("method", instance.getClass().getName() + ".writeObject()");
throw ex;
}
}
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){
ErrorWritingException ex = 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 (ObjectStreamField field2 : fields){
result.put(field2.getName(), field2);
}
}
}
}catch (final NoSuchFieldException e){}catch (final IllegalAccessException e){
ex = new ObjectAccessException("Cannot get field", e);
}catch (final ClassCastException e){
ex = new ConversionException("Incompatible field type", e);
}
if (ex != null){
ex.add("field", type.getName() + ".serialPersistentFields");
throw ex;
}
if (result == null){
result = NO_FIELDS;
}
fieldCache.put(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));
}
}