    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017    package org.apache.commons.lang;
    018
    019    import java.io.ByteArrayInputStream;
    020    import java.io.ByteArrayOutputStream;
    021    import java.io.IOException;
    022    import java.io.InputStream;
    023    import java.io.ObjectInputStream;
    024    import java.io.ObjectOutputStream;
    025    import java.io.OutputStream;
    026    import java.io.Serializable;
    027
    028    /**
    029     * <p>Assists with the serialization process and performs additional functionality based
    030     * on serialization.</p>
    031     * <p>
    032     * <ul>
    033     * <li>Deep clone using serialization
    034     * <li>Serialize managing finally and IOException
    035     * <li>Deserialize managing finally and IOException
    036     * </ul>
    037     *
    038     * <p>This class throws exceptions for invalid <code>null</code> inputs.
    039     * Each method documents its behaviour in more detail.</p>
    040     *
    041     * @author Apache Software Foundation
    042     * @author <a href="mailto:nissim@nksystems.com">Nissim Karpenstein</a>
    043     * @author <a href="mailto:janekdb@yahoo.co.uk">Janek Bogucki</a>
    044     * @author Daniel L. Rall
    045     * @author Jeff Varszegi
    046     * @author Gary Gregory
    047     * @since 1.0
    048     * @version $Id: SerializationUtils.java 905636 2010-02-02 14:03:32Z niallp $
    049     */
    050    public class SerializationUtils {
    051
    052        /**
    053         * <p>SerializationUtils instances should NOT be constructed in standard programming.
    054         * Instead, the class should be used as <code>SerializationUtils.clone(object)</code>.</p>
    055         *
    056         * <p>This constructor is public to permit tools that require a JavaBean instance
    057         * to operate.</p>
    058         * @since 2.0
    059         */
    060        public SerializationUtils() {
    061            super();
    062        }
    063
    064        // Clone
    065        //-----------------------------------------------------------------------
    066        /**
    067         * <p>Deep clone an <code>Object</code> using serialization.</p>
    068         *
    069         * <p>This is many times slower than writing clone methods by hand
    070         * on all objects in your object graph. However, for complex object
    071         * graphs, or for those that don't support deep cloning this can
    072         * be a simple alternative implementation. Of course all the objects
    073         * must be <code>Serializable</code>.</p>
    074         *
    075         * @param object  the <code>Serializable</code> object to clone
    076         * @return the cloned object
    077         * @throws SerializationException (runtime) if the serialization fails
    078         */
    079        public static Object clone(Serializable object) {
    080            return deserialize(serialize(object));
    081        }
    082
    083        // Serialize
    084        //-----------------------------------------------------------------------
    085        /**
    086         * <p>Serializes an <code>Object</code> to the specified stream.</p>
    087         *
    088         * <p>The stream will be closed once the object is written.
    089         * This avoids the need for a finally clause, and maybe also exception
    090         * handling, in the application code.</p>
    091         *
    092         * <p>The stream passed in is not buffered internally within this method.
    093         * This is the responsibility of your application if desired.</p>
    094         *
    095         * @param obj  the object to serialize to bytes, may be null
    096         * @param outputStream  the stream to write to, must not be null
    097         * @throws IllegalArgumentException if <code>outputStream</code> is <code>null</code>
    098         * @throws SerializationException (runtime) if the serialization fails
    099         */
    100        public static void serialize(Serializable obj, OutputStream outputStream) {
    101            if (outputStream == null) {
    102                throw new IllegalArgumentException("The OutputStream must not be null");
    103            }
    104            ObjectOutputStream out = null;
    105            try {
    106                // stream closed in the finally
    107                out = new ObjectOutputStream(outputStream);
    108                out.writeObject(obj);
    109
    110            } catch (IOException ex) {
    111                throw new SerializationException(ex);
    112            } finally {
    113                try {
    114                    if (out != null) {
    115                        out.close();
    116                    }
    117                } catch (IOException ex) {
    118                    // ignore close exception
    119                }
    120            }
    121        }
    122
    123        /**
    124         * <p>Serializes an <code>Object</code> to a byte array for
    125         * storage/serialization.</p>
    126         *
    127         * @param obj  the object to serialize to bytes
    128         * @return a byte[] with the converted Serializable
    129         * @throws SerializationException (runtime) if the serialization fails
    130         */
    131        public static byte[] serialize(Serializable obj) {
    132            ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
    133            serialize(obj, baos);
    134            return baos.toByteArray();
    135        }
    136
    137        // Deserialize
    138        //-----------------------------------------------------------------------
    139        /**
    140         * <p>Deserializes an <code>Object</code> from the specified stream.</p>
    141         *
    142         * <p>The stream will be closed once the object is written. This
    143         * avoids the need for a finally clause, and maybe also exception
    144         * handling, in the application code.</p>
    145         *
    146         * <p>The stream passed in is not buffered internally within this method.
    147         * This is the responsibility of your application if desired.</p>
    148         *
    149         * @param inputStream  the serialized object input stream, must not be null
    150         * @return the deserialized object
    151         * @throws IllegalArgumentException if <code>inputStream</code> is <code>null</code>
    152         * @throws SerializationException (runtime) if the serialization fails
    153         */
    154        public static Object deserialize(InputStream inputStream) {
    155            if (inputStream == null) {
    156                throw new IllegalArgumentException("The InputStream must not be null");
    157            }
    158            ObjectInputStream in = null;
    159            try {
    160                // stream closed in the finally
    161                in = new ObjectInputStream(inputStream);
    162                return in.readObject();
    163
    164            } catch (ClassNotFoundException ex) {
    165                throw new SerializationException(ex);
    166            } catch (IOException ex) {
    167                throw new SerializationException(ex);
    168            } finally {
    169                try {
    170                    if (in != null) {
    171                        in.close();
    172                    }
    173                } catch (IOException ex) {
    174                    // ignore close exception
    175                }
    176            }
    177        }
    178
    179        /**
    180         * <p>Deserializes a single <code>Object</code> from an array of bytes.</p>
    181         *
    182         * @param objectData  the serialized object, must not be null
    183         * @return the deserialized object
    184         * @throws IllegalArgumentException if <code>objectData</code> is <code>null</code>
    185         * @throws SerializationException (runtime) if the serialization fails
    186         */
    187        public static Object deserialize(byte[] objectData) {
    188            if (objectData == null) {
    189                throw new IllegalArgumentException("The byte[] must not be null");
    190            }
    191            ByteArrayInputStream bais = new ByteArrayInputStream(objectData);
    192            return deserialize(bais);
    193        }
    194
    195    }