diff --git a/core/src/main/java/org/hibernate/util/SerializationHelper.java b/core/src/main/java/org/hibernate/util/SerializationHelper.java index c875db33cf..cf458cae6e 100644 --- a/core/src/main/java/org/hibernate/util/SerializationHelper.java +++ b/core/src/main/java/org/hibernate/util/SerializationHelper.java @@ -36,6 +36,7 @@ import java.io.ObjectInputStream; import org.hibernate.type.SerializationException; import org.hibernate.Hibernate; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,148 +59,187 @@ import org.slf4j.LoggerFactory; * @author Stephen Colebourne * @author Jeff Varszegi * @author Gary Gregory - * @since 1.0 * @version $Id: SerializationHelper.java 9180 2006-01-30 23:51:27Z steveebersole $ + * @since 1.0 */ public final class SerializationHelper { - private static final Logger log = LoggerFactory.getLogger(SerializationHelper.class); + private static final Logger log = LoggerFactory.getLogger( SerializationHelper.class ); - private SerializationHelper() {} + private SerializationHelper() { + } - // Clone - //----------------------------------------------------------------------- - /** - *
Deep clone an Object
using serialization.
This is many times slower than writing clone methods by hand
- * on all objects in your object graph. However, for complex object
- * graphs, or for those that don't support deep cloning this can
- * be a simple alternative implementation. Of course all the objects
- * must be Serializable
.
Serializable
object to clone
- * @return the cloned object
- * @throws SerializationException (runtime) if the serialization fails
- */
- public static Object clone(Serializable object) throws SerializationException {
- log.trace("Starting clone through serialization");
+ // Clone
+ //-----------------------------------------------------------------------
+
+ /**
+ * Deep clone an Object
using serialization.
This is many times slower than writing clone methods by hand
+ * on all objects in your object graph. However, for complex object
+ * graphs, or for those that don't support deep cloning this can
+ * be a simple alternative implementation. Of course all the objects
+ * must be Serializable
.
Serializable
object to clone
+ *
+ * @return the cloned object
+ *
+ * @throws SerializationException (runtime) if the serialization fails
+ */
+ public static Object clone(Serializable object) throws SerializationException {
+ log.trace( "Starting clone through serialization" );
if ( object == null ) {
return null;
}
- return deserialize( serialize( object ), object.getClass().getClassLoader() );
- }
+ return deserialize( serialize( object ), object.getClass().getClassLoader() );
+ }
- // Serialize
- //-----------------------------------------------------------------------
- /**
- * Serializes an Object
to the specified stream.
The stream will be closed once the object is written. - * This avoids the need for a finally clause, and maybe also exception - * handling, in the application code.
- * - *The stream passed in is not buffered internally within this method. - * This is the responsibility of your application if desired.
- * - * @param obj the object to serialize to bytes, may be null - * @param outputStream the stream to write to, must not be null - * @throws IllegalArgumentException ifoutputStream
is null
- * @throws SerializationException (runtime) if the serialization fails
- */
- public static void serialize(Serializable obj, OutputStream outputStream) throws SerializationException {
- if (outputStream == null) {
- throw new IllegalArgumentException("The OutputStream must not be null");
- }
+ // Serialize
+ //-----------------------------------------------------------------------
- if ( log.isTraceEnabled() ) {
- if ( Hibernate.isInitialized( obj ) ) {
- log.trace( "Starting serialization of object [" + obj + "]" );
- }
- else {
- log.trace( "Starting serialization of [uninitialized proxy]" );
- }
- }
+ /**
+ * Serializes an Object
to the specified stream.
The stream will be closed once the object is written. + * This avoids the need for a finally clause, and maybe also exception + * handling, in the application code.
+ * + *The stream passed in is not buffered internally within this method. + * This is the responsibility of your application if desired.
+ * + * @param obj the object to serialize to bytes, may be null + * @param outputStream the stream to write to, must not be null + * + * @throws IllegalArgumentException ifoutputStream
is null
+ * @throws SerializationException (runtime) if the serialization fails
+ */
+ public static void serialize(Serializable obj, OutputStream outputStream) throws SerializationException {
+ if ( outputStream == null ) {
+ throw new IllegalArgumentException( "The OutputStream must not be null" );
+ }
- ObjectOutputStream out = null;
- try {
- // stream closed in the finally
- out = new ObjectOutputStream(outputStream);
- out.writeObject(obj);
+ if ( log.isTraceEnabled() ) {
+ if ( Hibernate.isInitialized( obj ) ) {
+ log.trace( "Starting serialization of object [" + obj + "]" );
+ }
+ else {
+ log.trace( "Starting serialization of [uninitialized proxy]" );
+ }
+ }
- }
- catch (IOException ex) {
- throw new SerializationException("could not serialize", ex);
- }
- finally {
- try {
- if (out != null) out.close();
- }
- catch (IOException ignored) {}
- }
- }
+ ObjectOutputStream out = null;
+ try {
+ // stream closed in the finally
+ out = new ObjectOutputStream( outputStream );
+ out.writeObject( obj );
- /**
- * Serializes an Object
to a byte array for
- * storage/serialization.
Serializes an Object
to a byte array for
+ * storage/serialization.
inputStream
is null
+ * @throws SerializationException (runtime) if the serialization fails
+ */
+ public static Object deserialize(InputStream inputStream) throws SerializationException {
+ return doDeserialize( inputStream, defaultClassLoader(), hibernateClassLoader(), null );
+ }
+
+ /**
+ * Returns the Thread Context ClassLoader (TCCL).
+ *
+ * @return The current TCCL
+ */
+ public static ClassLoader defaultClassLoader() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+
+ public static ClassLoader hibernateClassLoader() {
+ return SerializationHelper.class.getClassLoader();
+ }
+
+ /**
+ * Deserializes an object from the specified stream using the Thread Context
* ClassLoader (TCCL). If there is no TCCL set, the classloader of the calling
* class is used.
- *
- * Delegates to {@link #deserialize(java.io.InputStream, ClassLoader)}
- *
- * @param inputStream the serialized object input stream, must not be null
- * @return the deserialized object
- * @throws IllegalArgumentException if inputStream
is null
- * @throws SerializationException (runtime) if the serialization fails
- */
- public static Object deserialize(InputStream inputStream) throws SerializationException {
- return deserialize( inputStream, Thread.currentThread().getContextClassLoader() );
- }
-
- /**
- * Deserializes an object from the specified stream using the Thread Context
- * ClassLoader (TCCL). If there is no TCCL set, the classloader of the calling
- * class is used.
- *
- * The stream will be closed once the object is read. This avoids the need
+ *
+ * The stream will be closed once the object is read. This avoids the need
* for a finally clause, and maybe also exception handling, in the application
* code.
- *
- * The stream passed in is not buffered internally within this method. This is
+ *
+ * The stream passed in is not buffered internally within this method. This is
* the responsibility of the caller, if desired.
- *
- * @param inputStream the serialized object input stream, must not be null
+ *
+ * @param inputStream the serialized object input stream, must not be null
* @param loader The classloader to use
*
- * @return the deserialized object
+ * @return the deserialized object
*
- * @throws IllegalArgumentException if inputStream
is null
- * @throws SerializationException (runtime) if the serialization fails
- */
- public static Object deserialize(InputStream inputStream, ClassLoader loader) throws SerializationException {
- if (inputStream == null) {
- throw new IllegalArgumentException( "The InputStream must not be null" );
- }
+ * @throws IllegalArgumentException if inputStream
is null
+ * @throws SerializationException (runtime) if the serialization fails
+ */
+ public static Object deserialize(InputStream inputStream, ClassLoader loader) throws SerializationException {
+ return doDeserialize( inputStream, loader, defaultClassLoader(), hibernateClassLoader() );
+ }
+
+ public static Object doDeserialize(
+ InputStream inputStream,
+ ClassLoader loader,
+ ClassLoader fallbackLoader1,
+ ClassLoader fallbackLoader2) throws SerializationException {
+ if ( inputStream == null ) {
+ throw new IllegalArgumentException( "The InputStream must not be null" );
+ }
log.trace( "Starting deserialization of object" );
try {
- CustomObjectInputStream in = new CustomObjectInputStream( inputStream, loader );
+ CustomObjectInputStream in = new CustomObjectInputStream(
+ inputStream,
+ loader,
+ fallbackLoader1,
+ fallbackLoader2
+ );
try {
return in.readObject();
}
@@ -213,7 +253,7 @@ public final class SerializationHelper {
try {
in.close();
}
- catch (IOException ignore) {
+ catch ( IOException ignore ) {
// ignore
}
}
@@ -223,43 +263,48 @@ public final class SerializationHelper {
}
}
- /**
- * Deserializes an object from an array of bytes using the Thread Context
+ /**
+ * Deserializes an object from an array of bytes using the Thread Context
* ClassLoader (TCCL). If there is no TCCL set, the classloader of the calling
* class is used.
*
* Delegates to {@link #deserialize(byte[], ClassLoader)}
- *
- * @param objectData the serialized object, must not be null
- * @return the deserialized object
- * @throws IllegalArgumentException if objectData
is null
- * @throws SerializationException (runtime) if the serialization fails
- */
- public static Object deserialize(byte[] objectData) throws SerializationException {
- return deserialize( objectData, Thread.currentThread().getContextClassLoader() );
- }
+ *
+ * @param objectData the serialized object, must not be null
+ *
+ * @return the deserialized object
+ *
+ * @throws IllegalArgumentException if objectData
is null
+ * @throws SerializationException (runtime) if the serialization fails
+ */
+ public static Object deserialize(byte[] objectData) throws SerializationException {
+ return doDeserialize( wrap( objectData ), defaultClassLoader(), hibernateClassLoader(), null );
+ }
- /**
- * Deserializes an object from an array of bytes.
+ private static InputStream wrap(byte[] objectData) {
+ if ( objectData == null ) {
+ throw new IllegalArgumentException( "The byte[] must not be null" );
+ }
+ return new ByteArrayInputStream( objectData );
+ }
+
+ /**
+ * Deserializes an object from an array of bytes.
*
* Delegates to {@link #deserialize(java.io.InputStream, ClassLoader)} using a
- * {@link ByteArrayInputStream} to wrap the array.
- *
- * @param objectData the serialized object, must not be null
+ * {@link ByteArrayInputStream} to wrap the array.
+ *
+ * @param objectData the serialized object, must not be null
* @param loader The classloader to use
*
- * @return the deserialized object
+ * @return the deserialized object
*
- * @throws IllegalArgumentException if objectData
is null
- * @throws SerializationException (runtime) if the serialization fails
- */
- public static Object deserialize(byte[] objectData, ClassLoader loader) throws SerializationException {
- if ( objectData == null ) {
- throw new IllegalArgumentException( "The byte[] must not be null" );
- }
- ByteArrayInputStream bais = new ByteArrayInputStream( objectData );
- return deserialize( bais, loader );
- }
+ * @throws IllegalArgumentException if objectData
is null
+ * @throws SerializationException (runtime) if the serialization fails
+ */
+ public static Object deserialize(byte[] objectData, ClassLoader loader) throws SerializationException {
+ return doDeserialize( wrap( objectData ), loader, defaultClassLoader(), hibernateClassLoader() );
+ }
/**
@@ -271,11 +316,19 @@ public final class SerializationHelper {
* facilitate for that we allow passing in the class loader we should use.
*/
private static final class CustomObjectInputStream extends ObjectInputStream {
- private final ClassLoader loader;
+ private final ClassLoader loader1;
+ private final ClassLoader loader2;
+ private final ClassLoader loader3;
- private CustomObjectInputStream(InputStream in, ClassLoader loader) throws IOException {
+ private CustomObjectInputStream(
+ InputStream in,
+ ClassLoader loader1,
+ ClassLoader loader2,
+ ClassLoader loader3) throws IOException {
super( in );
- this.loader = loader;
+ this.loader1 = loader1;
+ this.loader2 = loader2;
+ this.loader3 = loader3;
}
/**
@@ -283,14 +336,29 @@ public final class SerializationHelper {
*/
protected Class resolveClass(ObjectStreamClass v) throws IOException, ClassNotFoundException {
String className = v.getName();
- log.trace("Attempting to locate class [" + className + "]");
+ log.trace( "Attempting to locate class [" + className + "]" );
- // if we were given a classloader, attempt to use it to resolve the class...
- if ( loader != null ) {
+ try {
+ return Class.forName( className, false, loader1 );
+ }
+ catch ( ClassNotFoundException e ) {
+ log.trace( "Unable to locate class using given classloader" );
+ }
+
+ if ( different( loader1, loader2 ) ) {
try {
- return Class.forName( className, false, loader );
+ return Class.forName( className, false, loader2 );
}
- catch (ClassNotFoundException e) {
+ catch ( ClassNotFoundException e ) {
+ log.trace( "Unable to locate class using given classloader" );
+ }
+ }
+
+ if ( different( loader1, loader3 ) && different( loader2, loader3 ) ) {
+ try {
+ return Class.forName( className, false, loader2 );
+ }
+ catch ( ClassNotFoundException e ) {
log.trace( "Unable to locate class using given classloader" );
}
}
@@ -299,5 +367,14 @@ public final class SerializationHelper {
// of the class which is calling this deserialization.
return super.resolveClass( v );
}
+
+ private boolean different(ClassLoader one, ClassLoader other) {
+ if ( one == null ) {
+ return other != null;
+ }
+ else {
+ return !one.equals( other );
+ }
+ }
}
}