All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.internal.util.SerializationHelper Maven / Gradle / Ivy

There is a newer version: 6.5.0.CR2
Show newest version
/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or .
 */
package org.hibernate.internal.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.OutputStream;
import java.io.Serializable;

import org.hibernate.Hibernate;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.type.SerializationException;

/**
 * 

Assists with the serialization process and performs additional functionality based * on serialization.

*

*

    *
  • Deep clone using serialization *
  • Serialize managing finally and IOException *
  • Deserialize managing finally and IOException *
*

*

This class throws exceptions for invalid null inputs. * Each method documents its behaviour in more detail.

* * @author Nissim Karpenstein * @author Janek Bogucki * @author Daniel Rall * @author Stephen Colebourne * @author Jeff Varszegi * @author Gary Gregory * * @since 1.0 */ public final class SerializationHelper { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( SerializationHelper.class ); 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.

* * @param object the 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() ); } // 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 if outputStream 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" ); } if ( LOG.isTraceEnabled() ) { if ( Hibernate.isInitialized( obj ) ) { LOG.tracev( "Starting serialization of object [{0}]", obj ); } else { LOG.trace( "Starting serialization of [uninitialized proxy]" ); } } ObjectOutputStream out = null; try { // stream closed in the finally out = new ObjectOutputStream( outputStream ); out.writeObject( obj ); } catch (IOException ex) { throw new SerializationException( "could not serialize", ex ); } finally { try { if ( out != null ) { out.close(); } } catch (IOException ignored) { } } } /** *

Serializes an Object to a byte array for * storage/serialization.

* * @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 byteArrayOutputStream = new ByteArrayOutputStream( 512 ); serialize( obj, byteArrayOutputStream ); return byteArrayOutputStream.toByteArray(); } // Deserialize //----------------------------------------------------------------------- /** * Deserializes an object from the specified stream using the Thread Context * ClassLoader (TCCL). *

* Delegates to {@link #doDeserialize} * * @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 T 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. *

* 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 responsibility of the caller, if desired. * * @param inputStream the serialized object input stream, must not be null * @param loader The classloader to use * * @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 { return doDeserialize( inputStream, loader, defaultClassLoader(), hibernateClassLoader() ); } @SuppressWarnings("unchecked") public static T 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, fallbackLoader1, fallbackLoader2 ); try { return (T) in.readObject(); } catch (ClassNotFoundException e) { throw new SerializationException( "could not deserialize", e ); } catch (IOException e) { throw new SerializationException( "could not deserialize", e ); } finally { try { in.close(); } catch (IOException ignore) { // ignore } } } catch (IOException e) { throw new SerializationException( "could not deserialize", e ); } } /** * 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 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 ); } /** * 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 * @param loader The classloader to use * * @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 { return doDeserialize( wrap( objectData ), loader, defaultClassLoader(), hibernateClassLoader() ); } /** * By default, to resolve the classes being deserialized JDK serialization uses the * classes loader which loaded the class which initiated the deserialization call. Here * that would be hibernate classes. However, there are cases where that is not the correct * class loader to use; mainly here we are worried about deserializing user classes in * environments (app servers, etc) where Hibernate is on a parent classes loader. To * facilitate for that we allow passing in the class loader we should use. */ private static final class CustomObjectInputStream extends ObjectInputStream { private final ClassLoader loader1; private final ClassLoader loader2; private final ClassLoader loader3; private CustomObjectInputStream( InputStream in, ClassLoader loader1, ClassLoader loader2, ClassLoader loader3) throws IOException { super( in ); this.loader1 = loader1; this.loader2 = loader2; this.loader3 = loader3; } /** * {@inheritDoc} */ @Override protected Class resolveClass(ObjectStreamClass v) throws IOException, ClassNotFoundException { final String className = v.getName(); LOG.tracev( "Attempting to locate class [{0}]", className ); 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, 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, loader3 ); } catch (ClassNotFoundException e) { LOG.trace( "Unable to locate class using given classloader" ); } } // By default delegate to normal JDK deserialization which will use the class loader // 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; } return !one.equals( other ); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy