/* Copyright (c) 2006-2009 Jan S. Rellermeyer * Systems Group, * Institute for Pervasive Computing, ETH Zurich. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - Neither the name of ETH Zurich nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package ch.ethz.iks.util; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Modifier; /** * Smart object input stream that is able to deserialize classes which do not * implement Serializable. It only rejects classes which have native code parts * and the OSGi ServiceReference and ServiceRegistration classes. * * @author Jan S. Rellermeyer * */ public final class SmartObjectInputStream extends ObjectInputStream { private final ObjectInputStream in; public SmartObjectInputStream(final InputStream in) throws IOException { // implicitly: super(); // thereby, enableOverride is set this.in = new ObjectInputStream(in); } protected final Object readObjectOverride() throws IOException, ClassNotFoundException { final byte cat = in.readByte(); switch (cat) { case 0: // null return null; case 1: // string serialized object // TODO: cache constructors try { final String type = in.readUTF(); final Class test = (Class) SmartConstants.idToClass.get(type); final Class clazz = test != null ? test : Class.forName(type); final Constructor constr = clazz .getConstructor(new Class[] { String.class }); return constr.newInstance(new Object[] { in.readUTF() }); } catch (final Exception e) { e.printStackTrace(); throw new IOException(e.getMessage()); } case 2: // java serialized object return in.readObject(); case 3: return readSmartSerializedObject(); case 4: final int length = in.readByte(); final String clazzName = in.readUTF(); final Class clazz = Class.forName(clazzName); final Object[] array = (Object[]) java.lang.reflect.Array .newInstance(clazz, length); for (int i = 0; i < length; i++) { final byte b = in.readByte(); if(b == -1) { array[i] = null; } else { array[i] = readSmartSerializedObject(); } } return array; default: throw new IllegalStateException("Unhandled case " + cat); //$NON-NLS-1$ } } private Object readSmartSerializedObject() throws IOException, ClassNotFoundException { // smart serialized object final String clazzName = in.readUTF(); // TODO: cache this information... Class clazz = Class.forName(clazzName); try { final Constructor constr = clazz.getDeclaredConstructor(null); constr.setAccessible(true); final Object newInstance = constr.newInstance(null); int fieldCount = in.readInt(); while (fieldCount > -1) { for (int i = 0; i < fieldCount; i++) { final String fieldName = in.readUTF(); final Object value = readObjectOverride(); final Field field = clazz.getDeclaredField(fieldName); final int mod = field.getModifiers(); if (!Modifier.isPublic(mod)) { field.setAccessible(true); } field.set(newInstance, value); } clazz = clazz.getSuperclass(); fieldCount = in.readInt(); } return newInstance; } catch (final Exception e) { e.printStackTrace(); throw new IOException("Error while deserializing " + clazzName //$NON-NLS-1$ + ": " + e.getMessage()); //$NON-NLS-1$ } } /** * * @see java.io.ObjectInputStream#read() */ public final int read() throws IOException { return in.read(); } /** * * @see java.io.ObjectInputStream#read(byte[], int, int) */ public final int read(final byte[] buf, final int off, final int len) throws IOException { return in.read(buf, off, len); } /** * * @see java.io.ObjectInputStream#available() */ public final int available() throws IOException { return in.available(); } /** * * @see java.io.ObjectInputStream#close() */ public final void close() throws IOException { in.close(); } /** * * @see java.io.ObjectInputStream#readBoolean() */ public final boolean readBoolean() throws IOException { return in.readBoolean(); } /** * * @see java.io.ObjectInputStream#readByte() */ public final byte readByte() throws IOException { return in.readByte(); } /** * * @see java.io.ObjectInputStream#readUnsignedByte() */ public final int readUnsignedByte() throws IOException { return in.readUnsignedByte(); } /** * * @see java.io.ObjectInputStream#readChar() */ public final char readChar() throws IOException { return in.readChar(); } /** * * @see java.io.ObjectInputStream#readShort() */ public final short readShort() throws IOException { return in.readShort(); } /** * * @see java.io.ObjectInputStream#readUnsignedShort() */ public final int readUnsignedShort() throws IOException { return in.readUnsignedShort(); } /** * * @see java.io.ObjectInputStream#readInt() */ public final int readInt() throws IOException { return in.readInt(); } /** * * @see java.io.ObjectInputStream#readLong() */ public final long readLong() throws IOException { return in.readLong(); } /** * * @see java.io.ObjectInputStream#readFloat() */ public final float readFloat() throws IOException { return in.readFloat(); } /** * * @see java.io.ObjectInputStream#readDouble() */ public final double readDouble() throws IOException { return in.readDouble(); } /** * * @see java.io.ObjectInputStream#readFully(byte[]) */ public final void readFully(final byte[] buf) throws IOException { in.readFully(buf); } /** * * @see java.io.ObjectInputStream#readFully(byte[], int, int) */ public final void readFully(final byte[] buf, final int off, final int len) throws IOException { in.readFully(buf, off, len); } /** * * @see java.io.ObjectInputStream#skipBytes(int) */ public final int skipBytes(final int len) throws IOException { return in.skipBytes(len); } /** * @return String * @throws IOException * @deprecated */ public final String readLine() throws IOException { return in.readLine(); } /** * * @see java.io.ObjectInputStream#readUTF() */ public final String readUTF() throws IOException { return in.readUTF(); } }