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 }