View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang;
18  
19  import java.io.ByteArrayInputStream;
20  import java.io.ByteArrayOutputStream;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.ObjectInputStream;
24  import java.io.ObjectOutputStream;
25  import java.io.OutputStream;
26  import java.io.Serializable;
27  
28  /**
29   * <p>Assists with the serialization process and performs additional functionality based 
30   * on serialization.</p>
31   * <p>
32   * <ul>
33   * <li>Deep clone using serialization
34   * <li>Serialize managing finally and IOException
35   * <li>Deserialize managing finally and IOException
36   * </ul>
37   *
38   * <p>This class throws exceptions for invalid <code>null</code> inputs.
39   * Each method documents its behaviour in more detail.</p>
40   *
41   * @author <a href="mailto:nissim@nksystems.com">Nissim Karpenstein</a>
42   * @author <a href="mailto:janekdb@yahoo.co.uk">Janek Bogucki</a>
43   * @author Daniel L. Rall
44   * @author Stephen Colebourne
45   * @author Jeff Varszegi
46   * @author Gary Gregory
47   * @since 1.0
48   * @version $Id: SerializationUtils.java 512889 2007-02-28 18:18:20Z dlr $
49   */
50  public class SerializationUtils {
51      
52      /**
53       * <p>SerializationUtils instances should NOT be constructed in standard programming.
54       * Instead, the class should be used as <code>SerializationUtils.clone(object)</code>.</p>
55       *
56       * <p>This constructor is public to permit tools that require a JavaBean instance
57       * to operate.</p>
58       * @since 2.0
59       */
60      public SerializationUtils() {
61          super();
62      }
63  
64      // Clone
65      //-----------------------------------------------------------------------
66      /**
67       * <p>Deep clone an <code>Object</code> using serialization.</p>
68       *
69       * <p>This is many times slower than writing clone methods by hand
70       * on all objects in your object graph. However, for complex object
71       * graphs, or for those that don't support deep cloning this can
72       * be a simple alternative implementation. Of course all the objects
73       * must be <code>Serializable</code>.</p>
74       * 
75       * @param object  the <code>Serializable</code> object to clone
76       * @return the cloned object
77       * @throws SerializationException (runtime) if the serialization fails
78       */
79      public static Object clone(Serializable object) {
80          return deserialize(serialize(object));
81      }
82      
83      // Serialize
84      //-----------------------------------------------------------------------
85      /**
86       * <p>Serializes an <code>Object</code> to the specified stream.</p>
87       *
88       * <p>The stream will be closed once the object is written.
89       * This avoids the need for a finally clause, and maybe also exception
90       * handling, in the application code.</p>
91       * 
92       * <p>The stream passed in is not buffered internally within this method.
93       * This is the responsibility of your application if desired.</p>
94       *
95       * @param obj  the object to serialize to bytes, may be null
96       * @param outputStream  the stream to write to, must not be null
97       * @throws IllegalArgumentException if <code>outputStream</code> is <code>null</code>
98       * @throws SerializationException (runtime) if the serialization fails
99       */
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 }