    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.lang3;
    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     * <p>#ThreadSafe#</p>
    042     * @author Apache Software Foundation
    043     * @author <a href="mailto:nissim@nksystems.com">Nissim Karpenstein</a>
    044     * @author <a href="mailto:janekdb@yahoo.co.uk">Janek Bogucki</a>
    045     * @author Daniel L. Rall
    046     * @author Jeff Varszegi
    047     * @author Gary Gregory
    048     * @since 1.0
    049     * @version $Id: SerializationUtils.java 918868 2010-03-04 06:22:16Z bayard $
    050     */
    051    public class SerializationUtils {
    052
    053        /**
    054         * <p>SerializationUtils instances should NOT be constructed in standard programming.
    055         * Instead, the class should be used as <code>SerializationUtils.clone(object)</code>.</p>
    056         *
    057         * <p>This constructor is public to permit tools that require a JavaBean instance
    058         * to operate.</p>
    059         * @since 2.0
    060         */
    061        public SerializationUtils() {
    062            super();
    063        }
    064
    065        // Clone
    066        //-----------------------------------------------------------------------
    067        /**
    068         * <p>Deep clone an <code>Object</code> using serialization.</p>
    069         *
    070         * <p>This is many times slower than writing clone methods by hand
    071         * on all objects in your object graph. However, for complex object
    072         * graphs, or for those that don't support deep cloning this can
    073         * be a simple alternative implementation. Of course all the objects
    074         * must be <code>Serializable</code>.</p>
    075         *
    076         * @param object  the <code>Serializable</code> object to clone
    077         * @return the cloned object
    078         * @throws SerializationException (runtime) if the serialization fails
    079         */
    080        public static Object clone(Serializable object) {
    081            return deserialize(serialize(object));
    082        }
    083
    084        // Serialize
    085        //-----------------------------------------------------------------------
    086        /**
    087         * <p>Serializes an <code>Object</code> to the specified stream.</p>
    088         *
    089         * <p>The stream will be closed once the object is written.
    090         * This avoids the need for a finally clause, and maybe also exception
    091         * handling, in the application code.</p>
    092         *
    093         * <p>The stream passed in is not buffered internally within this method.
    094         * This is the responsibility of your application if desired.</p>
    095         *
    096         * @param obj  the object to serialize to bytes, may be null
    097         * @param outputStream  the stream to write to, must not be null
    098         * @throws IllegalArgumentException if <code>outputStream</code> is <code>null</code>
    099         * @throws SerializationException (runtime) if the serialization fails
    100         */
    101        public static void serialize(Serializable obj, OutputStream outputStream) {
    102            if (outputStream == null) {
    103                throw new IllegalArgumentException("The OutputStream must not be null");
    104            }
    105            ObjectOutputStream out = null;
    106            try {
    107                // stream closed in the finally
    108                out = new ObjectOutputStream(outputStream);
    109                out.writeObject(obj);
    110
    111            } catch (IOException ex) {
    112                throw new SerializationException(ex);
    113            } finally {
    114                try {
    115                    if (out != null) {
    116                        out.close();
    117                    }
    118                } catch (IOException ex) {
    119                    // ignore close exception
    120                }
    121            }
    122        }
    123
    124        /**
    125         * <p>Serializes an <code>Object</code> to a byte array for
    126         * storage/serialization.</p>
    127         *
    128         * @param obj  the object to serialize to bytes
    129         * @return a byte[] with the converted Serializable
    130         * @throws SerializationException (runtime) if the serialization fails
    131         */
    132        public static byte[] serialize(Serializable obj) {
    133            ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
    134            serialize(obj, baos);
    135            return baos.toByteArray();
    136        }
    137
    138        // Deserialize
    139        //-----------------------------------------------------------------------
    140        /**
    141         * <p>Deserializes an <code>Object</code> from the specified stream.</p>
    142         *
    143         * <p>The stream will be closed once the object is written. This
    144         * avoids the need for a finally clause, and maybe also exception
    145         * handling, in the application code.</p>
    146         *
    147         * <p>The stream passed in is not buffered internally within this method.
    148         * This is the responsibility of your application if desired.</p>
    149         *
    150         * @param inputStream  the serialized object input stream, must not be null
    151         * @return the deserialized object
    152         * @throws IllegalArgumentException if <code>inputStream</code> is <code>null</code>
    153         * @throws SerializationException (runtime) if the serialization fails
    154         */
    155        public static Object deserialize(InputStream inputStream) {
    156            if (inputStream == null) {
    157                throw new IllegalArgumentException("The InputStream must not be null");
    158            }
    159            ObjectInputStream in = null;
    160            try {
    161                // stream closed in the finally
    162                in = new ObjectInputStream(inputStream);
    163                return in.readObject();
    164
    165            } catch (ClassNotFoundException ex) {
    166                throw new SerializationException(ex);
    167            } catch (IOException ex) {
    168                throw new SerializationException(ex);
    169            } finally {
    170                try {
    171                    if (in != null) {
    172                        in.close();
    173                    }
    174                } catch (IOException ex) {
    175                    // ignore close exception
    176                }
    177            }
    178        }
    179
    180        /**
    181         * <p>Deserializes a single <code>Object</code> from an array of bytes.</p>
    182         *
    183         * @param objectData  the serialized object, must not be null
    184         * @return the deserialized object
    185         * @throws IllegalArgumentException if <code>objectData</code> is <code>null</code>
    186         * @throws SerializationException (runtime) if the serialization fails
    187         */
    188        public static Object deserialize(byte[] objectData) {
    189            if (objectData == null) {
    190                throw new IllegalArgumentException("The byte[] must not be null");
    191            }
    192            ByteArrayInputStream bais = new ByteArrayInputStream(objectData);
    193            return deserialize(bais);
    194        }
    195
    196    }