Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* JBoss, Home of Professional Open Source
* Copyright 2008, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.marshalling.reflect;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.lang.reflect.Field;
import java.lang.ref.WeakReference;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.ObjectStreamException;
import java.io.ObjectStreamField;
import java.io.ObjectStreamClass;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Collections;
import java.util.concurrent.atomic.AtomicReference;
import java.security.AccessController;
import java.security.PrivilegedAction;
/**
* Reflection information about a serializable class. Intended for use by implementations of the Marshalling API.
*/
public final class SerializableClass {
private final WeakReference> subjectRef;
private final LazyWeakMethodRef writeObject;
private final LazyWeakMethodRef writeReplace;
private final LazyWeakMethodRef readObject;
private final LazyWeakMethodRef readObjectNoData;
private final LazyWeakMethodRef readResolve;
private final SerializableField[] fields;
private final long effectiveSerialVersionUID;
private static final Comparator super SerializableField> NAME_COMPARATOR = new Comparator() {
public int compare(final SerializableField o1, final SerializableField o2) {
return o1.getName().compareTo(o2.getName());
}
};
public static final SerializableField[] NOFIELDS = new SerializableField[0];
SerializableClass(Class> subject) {
final WeakReference> subjectRef = new WeakReference>(subject);
this.subjectRef = subjectRef;
writeObject = LazyWeakMethodRef.getInstance(new MethodFinder() {
public Method get(Class> clazz) {
return lookupPrivateMethod(clazz, "writeObject", ObjectOutputStream.class);
}
}, subjectRef);
readObject = LazyWeakMethodRef.getInstance(new MethodFinder() {
public Method get(final Class> clazz) {
return lookupPrivateMethod(clazz, "readObject", ObjectInputStream.class);
}
}, subjectRef);
readObjectNoData = LazyWeakMethodRef.getInstance(new MethodFinder() {
public Method get(final Class> clazz) {
return lookupPrivateMethod(clazz, "readObjectNoData");
}
}, subjectRef);
writeReplace = LazyWeakMethodRef.getInstance(new MethodFinder() {
public Method get(final Class> clazz) {
return lookupInheritableMethod(clazz, "writeReplace");
}
}, subjectRef);
readResolve = LazyWeakMethodRef.getInstance(new MethodFinder() {
public Method get(final Class> clazz) {
return lookupInheritableMethod(clazz, "readResolve");
}
}, subjectRef);
final ObjectStreamClass objectStreamClass = ObjectStreamClass.lookup(subject);
effectiveSerialVersionUID = objectStreamClass == null ? 0L : objectStreamClass.getSerialVersionUID(); // todo find a better solution
fields = getSerializableFields(subject);
}
private static SerializableField[] getSerializableFields(Class> clazz) {
final ObjectStreamField[] objectStreamFields = getDeclaredSerialPersistentFields(clazz);
if (objectStreamFields != null) {
SerializableField[] fields = new SerializableField[objectStreamFields.length];
for (int i = 0; i < objectStreamFields.length; i++) {
ObjectStreamField field = objectStreamFields[i];
fields[i] = new SerializableField(clazz, field.getType(), field.getName(), field.isUnshared());
}
Arrays.sort(fields, NAME_COMPARATOR);
return fields;
}
// not declared; we'll have to dig through the class's fields
final Field[] declaredFields = clazz.getDeclaredFields();
final ArrayList fields = new ArrayList(declaredFields.length);
for (Field field : declaredFields) {
if ((field.getModifiers() & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) {
fields.add(new SerializableField(clazz, field.getType(), field.getName(), false));
}
}
Collections.sort(fields, NAME_COMPARATOR);
return fields.toArray(new SerializableField[fields.size()]);
}
private static ObjectStreamField[] getDeclaredSerialPersistentFields(Class> clazz) {
final Field field;
try {
field = clazz.getDeclaredField("serialPersistentFields");
} catch (NoSuchFieldException e) {
return null;
}
if (field == null) {
return null;
}
final int requiredModifiers = Modifier.STATIC | Modifier.PRIVATE | Modifier.FINAL;
if ((field.getModifiers() & requiredModifiers) != requiredModifiers) {
return null;
}
field.setAccessible(true);
try {
return (ObjectStreamField[]) field.get(null);
} catch (IllegalAccessException e) {
return null;
} catch (ClassCastException e) {
return null;
}
}
/**
* Get the serializable fields of this class. The returned array is a direct reference, so care should be taken
* not to modify it.
*
* @return the fields
*/
public SerializableField[] getFields() {
return fields;
}
/**
* Create a synthetic field for this object class.
*
* @param name the name of the field
* @param fieldType the field type
* @param unshared {@code true} if the field should be unshared
* @return the field
* @throws ClassNotFoundException if a class was not found while looking up the subject class
*/
public SerializableField getSerializableField(String name, Class> fieldType, boolean unshared) throws ClassNotFoundException {
return new SerializableField(getSubjectClass(), fieldType, name, unshared);
}
/**
* Determine whether this class has a {@code writeObject()} method.
*
* @return {@code true} if there is a {@code writeObject()} method
*/
public boolean hasWriteObject() {
return writeObject != null;
}
/**
* Invoke the {@code writeObject()} method for an object.
*
* @param object the object to invoke on
* @param outputStream the object output stream to pass in
* @throws IOException if an I/O error occurs
*/
public void callWriteObject(Object object, ObjectOutputStream outputStream) throws IOException {
try {
writeObject.getMethod().invoke(object, outputStream);
} catch (InvocationTargetException e) {
final Throwable te = e.getTargetException();
if (te instanceof IOException) {
throw (IOException)te;
} else if (te instanceof RuntimeException) {
throw (RuntimeException)te;
} else if (te instanceof Error) {
throw (Error)te;
} else {
throw new IllegalStateException("Unexpected exception", te);
}
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Class is unexpectedly missing or changed");
} catch (IllegalAccessException e) {
throw new IllegalStateException("Method is unexpectedly inaccessible");
}
}
/**
* Determine whether this class has a {@code readObject()} method.
*
* @return {@code true} if there is a {@code readObject()} method
*/
public boolean hasReadObject() {
return readObject != null;
}
/**
* Invoke the {@code readObject()} method for an object.
*
* @param object the object to invoke on
* @param inputStream the object input stream to pass in
* @throws IOException if an I/O error occurs
* @throws ClassNotFoundException if a class was not able to be loaded
*/
public void callReadObject(Object object, ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
try {
readObject.getMethod().invoke(object, inputStream);
} catch (InvocationTargetException e) {
final Throwable te = e.getTargetException();
if (te instanceof IOException) {
throw (IOException)te;
} else if (te instanceof ClassNotFoundException) {
throw (ClassNotFoundException)te;
} else if (te instanceof RuntimeException) {
throw (RuntimeException)te;
} else if (te instanceof Error) {
throw (Error)te;
} else {
throw new IllegalStateException("Unexpected exception", te);
}
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Class is unexpectedly missing or changed");
} catch (IllegalAccessException e) {
throw new IllegalStateException("Method is unexpectedly inaccessible");
}
}
/**
* Determine whether this class has a {@code readObjectNoData()} method.
*
* @return {@code true} if there is a {@code readObjectNoData()} method
*/
public boolean hasReadObjectNoData() {
return readObjectNoData != null;
}
/**
* Invoke the {@code readObjectNoData()} method for an object.
*
* @param object the object to invoke on
* @throws ObjectStreamException if an I/O error occurs
*/
public void callReadObjectNoData(Object object) throws ObjectStreamException {
try {
readObjectNoData.getMethod().invoke(object);
} catch (InvocationTargetException e) {
final Throwable te = e.getTargetException();
if (te instanceof ObjectStreamException) {
throw (ObjectStreamException)te;
} else if (te instanceof RuntimeException) {
throw (RuntimeException)te;
} else if (te instanceof Error) {
throw (Error)te;
} else {
throw new IllegalStateException("Unexpected exception", te);
}
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Class is unexpectedly missing or changed");
} catch (IllegalAccessException e) {
throw new IllegalStateException("Method is unexpectedly inaccessible");
}
}
/**
* Determine whether this class has a {@code writeReplace()} method.
*
* @return {@code true} if there is a {@code writeReplace()} method
*/
public boolean hasWriteReplace() {
return writeReplace != null;
}
/**
* Invoke the {@code writeReplace()} method for an object.
*
* @param object the object to invoke on
* @return the nominated replacement object
* @throws ObjectStreamException if an I/O error occurs
*/
public Object callWriteReplace(Object object) throws ObjectStreamException {
try {
return writeReplace.getMethod().invoke(object);
} catch (InvocationTargetException e) {
final Throwable te = e.getTargetException();
if (te instanceof ObjectStreamException) {
throw (ObjectStreamException)te;
} else if (te instanceof RuntimeException) {
throw (RuntimeException)te;
} else if (te instanceof Error) {
throw (Error)te;
} else {
throw new IllegalStateException("Unexpected exception", te);
}
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Class is unexpectedly missing or changed");
} catch (IllegalAccessException e) {
throw new IllegalStateException("Method is unexpectedly inaccessible");
}
}
/**
* Determine whether this class has a {@code readResolve()} method.
*
* @return {@code true} if there is a {@code readResolve()} method
*/
public boolean hasReadResolve() {
return readResolve != null;
}
/**
* Invoke the {@code readResolve()} method for an object.
*
* @param object the object to invoke on
* @return the original object
* @throws ObjectStreamException if an I/O error occurs
*/
public Object callReadResolve(Object object) throws ObjectStreamException {
try {
return readResolve.getMethod().invoke(object);
} catch (InvocationTargetException e) {
final Throwable te = e.getTargetException();
if (te instanceof ObjectStreamException) {
throw (ObjectStreamException)te;
} else if (te instanceof RuntimeException) {
throw (RuntimeException)te;
} else if (te instanceof Error) {
throw (Error)te;
} else {
throw new IllegalStateException("Unexpected exception", te);
}
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Class is unexpectedly missing or changed");
} catch (IllegalAccessException e) {
throw new IllegalStateException("Method is unexpectedly inaccessible");
}
}
/**
* Get the effective serial version UID of this class.
*
* @return the serial version UID
*/
public long getEffectiveSerialVersionUID() {
return effectiveSerialVersionUID;
}
/**
* Get the {@code Class} of this class.
*
* @return the subject class
* @throws ClassNotFoundException if the class was unloaded
*/
public Class> getSubjectClass() throws ClassNotFoundException {
return dereference(subjectRef);
}
private static Method lookupPrivateMethod(final Class> subject, final String name, final Class>... params) {
return AccessController.doPrivileged(new PrivilegedAction() {
public Method run() {
try {
final Method method = subject.getDeclaredMethod(name, params);
final int modifiers = method.getModifiers();
if ((modifiers & Modifier.PRIVATE) == 0) {
// must be private...
return null;
} else if ((modifiers & Modifier.STATIC) != 0) {
// must NOT be static...
return null;
} else {
method.setAccessible(true);
return method;
}
} catch (NoSuchMethodException e) {
return null;
}
}
});
}
private static Method lookupInheritableMethod(final Class> subject, final String name) {
return AccessController.doPrivileged(new PrivilegedAction() {
public Method run() {
Class> foundClass = subject;
Method method = null;
while (method == null) {
try {
if (foundClass == null) {
return null;
}
method = foundClass.getDeclaredMethod(name);
if (method == null) {
foundClass = foundClass.getSuperclass();
}
} catch (NoSuchMethodException e) {
foundClass = foundClass.getSuperclass();
continue;
}
}
final int modifiers = method.getModifiers();
if ((modifiers & Modifier.STATIC) != 0) {
// must NOT be static..
return null;
} else if ((modifiers & Modifier.ABSTRACT) != 0) {
// must NOT be abstract...
return null;
} else if ((modifiers & Modifier.PRIVATE) != 0 && foundClass != subject) {
// not visible to the actual class
return null;
} else if ((modifiers & (Modifier.PROTECTED | Modifier.PUBLIC)) != 0 || isSamePackage(foundClass, subject)) {
// visible!
method.setAccessible(true);
return method;
} else {
// package private, but not the same package
return null;
}
}
});
}
// the package is the same if the name and classloader are both the same
private static boolean isSamePackage(Class> a, Class> b) {
return a.getClassLoader() == b.getClassLoader() && getPackageName(a).equals(getPackageName(b));
}
private static String getPackageName(Class> c) {
String name = c.getName();
// skip array part
int idx = name.lastIndexOf('[');
if (idx > -1) {
// [[[[Lfoo.bar.baz.Blah;
// skip [ and also the L
name = name.substring(idx + 2);
}
idx = name.lastIndexOf('.');
if (idx > -1) {
// foo.bar.baz.Blah;
name = name.substring(0, idx);
return name;
} else {
// no package
return "";
}
}
private interface MethodFinder {
Method get(Class> clazz);
}
static Class> dereference(final WeakReference> classRef) throws ClassNotFoundException {
final Class> clazz = classRef.get();
if (clazz == null) {
throw new ClassNotFoundException("Class was unloaded");
}
return clazz;
}
private static class LazyWeakMethodRef {
private final AtomicReference> ref;
private final MethodFinder finder;
private final WeakReference> classRef;
private LazyWeakMethodRef(final MethodFinder finder, final Method initial, final WeakReference> classRef) {
this.finder = finder;
this.classRef = classRef;
ref = new AtomicReference>(new WeakReference(initial));
}
private static LazyWeakMethodRef getInstance(MethodFinder finder, WeakReference> classRef) {
final Class> clazz = classRef.get();
if (clazz == null) {
throw new NullPointerException("clazz is null (no strong reference held to class when serialization info was acquired");
}
final Method method = finder.get(clazz);
if (method == null) {
return null;
}
return new LazyWeakMethodRef(finder, method, classRef);
}
private Method getMethod() throws ClassNotFoundException {
final WeakReference weakReference = ref.get();
if (weakReference != null) {
final Method method = weakReference.get();
if (method != null) {
return method;
}
}
final Class> clazz = dereference(classRef);
final Method method = finder.get(clazz);
if (method == null) {
throw new NullPointerException("method is null (was non-null on last check)");
}
final WeakReference newVal = new WeakReference(method);
ref.compareAndSet(weakReference, newVal);
return method;
}
}
}