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 }