HHH-4786 - SerializableType + custom Serializable class + L2 cache causes problems

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18544 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2010-01-13 19:45:07 +00:00
parent 9256bc30e5
commit fca1248487
1 changed files with 228 additions and 151 deletions

View File

@ -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,17 +59,19 @@ 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 SerializationHelper() {}
private SerializationHelper() {
}
// Clone
//-----------------------------------------------------------------------
/**
* <p>Deep clone an <code>Object</code> using serialization.</p>
*
@ -79,7 +82,9 @@ public final class SerializationHelper {
* must be <code>Serializable</code>.</p>
*
* @param object the <code>Serializable</code> object to clone
*
* @return the cloned object
*
* @throws SerializationException (runtime) if the serialization fails
*/
public static Object clone(Serializable object) throws SerializationException {
@ -92,6 +97,7 @@ public final class SerializationHelper {
// Serialize
//-----------------------------------------------------------------------
/**
* <p>Serializes an <code>Object</code> to the specified stream.</p>
*
@ -104,6 +110,7 @@ public final class SerializationHelper {
*
* @param obj the object to serialize to bytes, may be null
* @param outputStream the stream to write to, must not be null
*
* @throws IllegalArgumentException if <code>outputStream</code> is <code>null</code>
* @throws SerializationException (runtime) if the serialization fails
*/
@ -133,9 +140,12 @@ public final class SerializationHelper {
}
finally {
try {
if (out != null) out.close();
if ( out != null ) {
out.close();
}
}
catch ( IOException ignored ) {
}
catch (IOException ignored) {}
}
}
@ -144,31 +154,48 @@ public final class SerializationHelper {
* storage/serialization.</p>
*
* @param obj the object to serialize to bytes
*
* @return a byte[] with the converted Serializable
*
* @throws SerializationException (runtime) if the serialization fails
*/
public static byte[] serialize(Serializable obj) throws SerializationException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
serialize(obj, baos);
return baos.toByteArray();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream( 512 );
serialize( obj, byteArrayOutputStream );
return byteArrayOutputStream.toByteArray();
}
// Deserialize
//-----------------------------------------------------------------------
/**
* 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.
* ClassLoader (TCCL).
* <p/>
* Delegates to {@link #deserialize(java.io.InputStream, ClassLoader)}
* Delegates to {@link #doDeserialize}
*
* @param inputStream the serialized object input stream, must not be null
*
* @return the deserialized object
*
* @throws IllegalArgumentException if <code>inputStream</code> is <code>null</code>
* @throws SerializationException (runtime) if the serialization fails
*/
public static Object deserialize(InputStream inputStream) throws SerializationException {
return deserialize( inputStream, Thread.currentThread().getContextClassLoader() );
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();
}
/**
@ -192,6 +219,14 @@ public final class SerializationHelper {
* @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" );
}
@ -199,7 +234,12 @@ public final class SerializationHelper {
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();
}
@ -231,12 +271,21 @@ public final class SerializationHelper {
* Delegates to {@link #deserialize(byte[], ClassLoader)}
*
* @param objectData the serialized object, must not be null
*
* @return the deserialized object
*
* @throws IllegalArgumentException if <code>objectData</code> is <code>null</code>
* @throws SerializationException (runtime) if the serialization fails
*/
public static Object deserialize(byte[] objectData) throws SerializationException {
return deserialize( objectData, Thread.currentThread().getContextClassLoader() );
return doDeserialize( wrap( objectData ), defaultClassLoader(), hibernateClassLoader(), null );
}
private static InputStream wrap(byte[] objectData) {
if ( objectData == null ) {
throw new IllegalArgumentException( "The byte[] must not be null" );
}
return new ByteArrayInputStream( objectData );
}
/**
@ -254,11 +303,7 @@ public final class SerializationHelper {
* @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 );
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;
}
/**
@ -285,10 +338,25 @@ public final class SerializationHelper {
String className = v.getName();
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, loader );
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, loader2 );
}
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 );
}
}
}
}