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