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 }