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 }