001 /*--------------------------------------------------------------------------+
002 $Id: SerializationUtils.java 29381 2010-07-27 11:29:07Z deissenb $
003 | |
004 | Copyright 2005-2010 Technische Universitaet Muenchen |
005 | |
006 | Licensed under the Apache License, Version 2.0 (the "License"); |
007 | you may not use this file except in compliance with the License. |
008 | You may obtain a copy of the License at |
009 | |
010 | http://www.apache.org/licenses/LICENSE-2.0 |
011 | |
012 | Unless required by applicable law or agreed to in writing, software |
013 | distributed under the License is distributed on an "AS IS" BASIS, |
014 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
015 | See the License for the specific language governing permissions and |
016 | limitations under the License. |
017 +--------------------------------------------------------------------------*/
018 package edu.tum.cs.commons.io;
019
020 import java.io.ByteArrayInputStream;
021 import java.io.ByteArrayOutputStream;
022 import java.io.IOException;
023 import java.io.ObjectInputStream;
024 import java.io.ObjectOutputStream;
025 import java.io.ObjectStreamClass;
026 import java.io.Serializable;
027
028 import edu.tum.cs.commons.assertion.CCSMAssert;
029 import edu.tum.cs.commons.filesystem.FileSystemUtils;
030
031 /**
032 * Utility methods for serialization.
033 *
034 * @author hummelb
035 * @author $Author: deissenb $
036 * @version $Rev: 29381 $
037 * @levd.rating GREEN Hash: CE4B1240AC4E61F91653F44688B311C5
038 */
039 public class SerializationUtils {
040
041 /** Serializes an object to byte array */
042 public static byte[] serializeToByteArray(Serializable object)
043 throws IOException {
044 ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();
045 ObjectOutputStream out = new ObjectOutputStream(outBuffer);
046 out.writeObject(object);
047 // no need to put this in finally, as we do not block file handles.
048 // Let the GC do the work
049 out.close();
050 return outBuffer.toByteArray();
051 }
052
053 /**
054 * Deserializes an object from byte array using the default class loader
055 * used in {@link ObjectInputStream}, i.e. if there is a method on the
056 * current call stack whose class was loaded via a custom class loader, this
057 * class loader is used. Otherwise the default class loader is used. Also
058 * see the documentation of {@link ObjectInputStream}s resolveClass()
059 * method.
060 */
061 public static Serializable deserializeFromByteArray(byte[] bytes)
062 throws IOException, ClassNotFoundException {
063 return deserializeFromByteArray(bytes, null);
064 }
065
066 /**
067 * Deserializes an object from byte array using a custom/given class loader.
068 *
069 * @param classLoader
070 * the class loader used. If this is null, the default behavior
071 * of {@link ObjectInputStream} is used, i.e. if there is a
072 * method on the current call stack whose class was loaded via a
073 * custom class loader, this class loader is used. Otherwise the
074 * default class loader is used. Also see the documentation of
075 * {@link ObjectInputStream}s resolveClass() method.
076 */
077 public static Serializable deserializeFromByteArray(byte[] bytes,
078 final ClassLoader classLoader) throws IOException,
079 ClassNotFoundException {
080
081 ObjectInputStream in;
082 if (classLoader == null) {
083 in = new ObjectInputStream(new ByteArrayInputStream(bytes));
084 } else {
085 // it seems that the only solution to use a custom class loader is
086 // to override a method in the ObjectInputStream class. This is
087 // confirmed by
088 // http://blogs.sun.com/adventures/entry/desrializing_objects_custom_class_loaders
089 // and seems plausible as the corresponding method is protected.
090
091 in = new ObjectInputStream(new ByteArrayInputStream(bytes)) {
092
093 /** {@inheritDoc} */
094 @Override
095 protected Class<?> resolveClass(ObjectStreamClass desc)
096 throws IOException, ClassNotFoundException {
097 try {
098 return Class
099 .forName(desc.getName(), false, classLoader);
100 } catch (ClassNotFoundException e) {
101 // as a fallback we pass this to the super method, as
102 // for example primitive values are treated there.
103 return super.resolveClass(desc);
104 }
105 }
106 };
107 }
108
109 try {
110 return (Serializable) in.readObject();
111 } finally {
112 FileSystemUtils.close(in);
113 }
114 }
115
116 /**
117 * Returns a copy of the given object obtained by serialization and
118 * deserialization in memory.
119 *
120 * @param classLoader
121 * the class loader used. If this is null, the default behavior
122 * of {@link ObjectInputStream} is used, i.e. if there is a
123 * method on the current call stack whose class was loaded via a
124 * custom class loader, this class loader is used. Otherwise the
125 * default class loader is used. Also see the documentation of
126 * {@link ObjectInputStream}s resolveClass() method.
127 */
128 @SuppressWarnings("unchecked")
129 public static <T extends Serializable> T cloneBySerialization(T t,
130 ClassLoader classLoader) {
131 try {
132 return (T) deserializeFromByteArray(serializeToByteArray(t),
133 classLoader);
134 } catch (IOException e) {
135 CCSMAssert
136 .fail("This should be impossible as we are working in memory!");
137 return null;
138 } catch (ClassNotFoundException e) {
139 CCSMAssert
140 .fail("This should be impossible as we just had the object available!");
141 return null;
142 }
143 }
144
145 /**
146 * Inserts an int value to the given position in the byte array. The storage
147 * will require 4 bytes in big endian byte order.
148 */
149 public static void insertInt(int i, byte[] bytes, int position) {
150 bytes[position++] = (byte) (i >> 24 & 0xff);
151 bytes[position++] = (byte) (i >> 16 & 0xff);
152 bytes[position++] = (byte) (i >> 8 & 0xff);
153 bytes[position] = (byte) (i & 0xff);
154 }
155
156 /**
157 * Extracts an int value from the given array position (4 bytes in big
158 * endian). This is the counter part to {@link #insertInt(int, byte[], int)}
159 * .
160 */
161 public static int extractInt(byte[] bytes, int position) {
162 int result = bytes[position++] & 0xff;
163 result <<= 8;
164 result |= bytes[position++] & 0xff;
165 result <<= 8;
166 result |= bytes[position++] & 0xff;
167 result <<= 8;
168 result |= bytes[position++] & 0xff;
169 return result;
170 }
171
172 }