blob: be03dd0c8ce7833c51c2a3bf1c06e9841c5b2ff8 [file] [log] [blame]
/* 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.NotSerializableException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import ch.ethz.iks.r_osgi.types.BoxedPrimitive;
/**
* Smart object output 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 SmartObjectOutputStream extends ObjectOutputStream {
private final ObjectOutputStream out;
public SmartObjectOutputStream(final OutputStream out) throws IOException {
// implicitly: super();
// thereby, enableOverride is set
this.out = new ObjectOutputStream(out);
}
protected final void writeObjectOverride(final Object o) throws IOException {
if (o == null) {
out.writeByte(0);
return;
}
final Object obj = o instanceof BoxedPrimitive ? ((BoxedPrimitive) o)
.getBoxed() : o;
final String clazzName = obj.getClass().getName();
if (SmartConstants.positiveList.contains(clazzName)) {
// string serializable classes
out.writeByte(1);
final String id = (String) SmartConstants.classToId.get(clazzName);
out.writeUTF(id != null ? id : clazzName);
out.writeUTF(obj.toString());
return;
} else if (obj instanceof Serializable) {
// java serializable classes
out.writeByte(2);
out.writeObject(obj);
return;
} else {
out.writeByte(3);
// all other classes: try smart serialization
Class clazz = obj.getClass();
if (SmartConstants.blackList.contains(clazz.getName())) {
throw new NotSerializableException("Class " + clazz.getName() //$NON-NLS-1$
+ " is not serializable"); //$NON-NLS-1$
}
out.writeUTF(clazz.getName());
// TODO: cache this information...
while (clazz != Object.class) {
// check for native methods
final Method[] methods = clazz.getDeclaredMethods();
for (int j = 0; j < methods.length; j++) {
final int mod = methods[j].getModifiers();
if (Modifier.isNative(mod)) {
throw new NotSerializableException(
"Class " //$NON-NLS-1$
+ clazz.getName()
+ " contains native methods and is therefore not serializable."); //$NON-NLS-1$
}
}
try {
final Field[] fields = clazz.getDeclaredFields();
final int fieldCount = fields.length;
out.writeInt(fieldCount);
for (int i = 0; i < fieldCount; i++) {
final int mod = fields[i].getModifiers();
if (Modifier.isStatic(mod)) {
continue;
} else if (!Modifier.isPublic(mod)) {
fields[i].setAccessible(true);
}
out.writeUTF(fields[i].getName());
writeObjectOverride(fields[i].get(obj));
}
} catch (final Exception e) {
throw new NotSerializableException(
"Exception while serializing " + obj.toString() //$NON-NLS-1$
+ ":\n" + e.getMessage()); //$NON-NLS-1$
}
clazz = clazz.getSuperclass();
}
out.writeInt(-1);
}
}
/**
*
* @see java.io.ObjectOutputStream#write(int)
*/
public final void write(final int val) throws IOException {
out.write(val);
}
/**
*
* @see java.io.ObjectOutputStream#write(byte[])
*/
public final void write(final byte[] buf) throws IOException {
out.write(buf);
}
/**
*
* @see java.io.ObjectOutputStream#write(byte[], int, int)
*/
public final void write(final byte[] buf, final int off, final int len)
throws IOException {
out.write(buf, off, len);
}
/**
*
* @see java.io.ObjectOutputStream#flush()
*/
public final void flush() throws IOException {
out.flush();
}
/**
*
* @see java.io.ObjectOutputStream#reset()
*/
public final void reset() throws IOException {
out.reset();
}
/**
*
* @see java.io.ObjectOutputStream#close()
*/
public final void close() throws IOException {
out.close();
}
/**
*
* @see java.io.ObjectOutputStream#writeBoolean(boolean)
*/
public final void writeBoolean(final boolean val) throws IOException {
out.writeBoolean(val);
}
/**
*
* @see java.io.ObjectOutputStream#writeByte(int)
*/
public final void writeByte(final int val) throws IOException {
out.writeByte(val);
}
/**
*
* @see java.io.ObjectOutputStream#writeShort(int)
*/
public final void writeShort(final int val) throws IOException {
out.writeShort(val);
}
/**
*
* @see java.io.ObjectOutputStream#writeChar(int)
*/
public final void writeChar(final int val) throws IOException {
out.writeChar(val);
}
/**
*
* @see java.io.ObjectOutputStream#writeInt(int)
*/
public final void writeInt(final int val) throws IOException {
out.writeInt(val);
}
/**
*
* @see java.io.ObjectOutputStream#writeLong(long)
*/
public final void writeLong(final long val) throws IOException {
out.writeLong(val);
}
/**
*
* @see java.io.ObjectOutputStream#writeFloat(float)
*/
public final void writeFloat(final float val) throws IOException {
out.writeFloat(val);
}
/**
*
* @see java.io.ObjectOutputStream#writeDouble(double)
*/
public final void writeDouble(final double val) throws IOException {
out.writeDouble(val);
}
/**
*
* @see java.io.ObjectOutputStream#writeBytes(java.lang.String)
*/
public final void writeBytes(final String str) throws IOException {
out.writeBytes(str);
}
/**
*
* @see java.io.ObjectOutputStream#writeChars(java.lang.String)
*/
public final void writeChars(final String str) throws IOException {
out.writeChars(str);
}
/**
*
* @see java.io.ObjectOutputStream#writeUTF(java.lang.String)
*/
public final void writeUTF(final String str) throws IOException {
out.writeUTF(str);
}
}