001: package org.drools.objenesis.instantiator.basic;
002:
003: import java.io.ByteArrayOutputStream;
004: import java.io.DataOutputStream;
005: import java.io.IOException;
006: import java.io.InputStream;
007: import java.io.NotSerializableException;
008: import java.io.ObjectInputStream;
009: import java.io.ObjectStreamClass;
010: import java.io.ObjectStreamConstants;
011: import java.io.Serializable;
012:
013: import org.drools.objenesis.ObjenesisException;
014: import org.drools.objenesis.instantiator.ObjectInstantiator;
015:
016: /**
017: * Instantiates a class by using a dummy input stream that always feeds data for an empty object of
018: * the same kind. NOTE: This instantiator may not work properly if the class being instantiated
019: * defines a "readResolve" method, since it may return objects that have been returned previously
020: * (i.e., there's no guarantee that the returned object is a new one), or even objects from a
021: * completely different class.
022: *
023: * @author Leonardo Mesquita
024: * @see org.drools.objenesis.instantiator.ObjectInstantiator
025: */
026: public class ObjectInputStreamInstantiator implements
027: ObjectInstantiator {
028: private static class MockStream extends InputStream {
029:
030: private int pointer;
031: private byte[] data;
032: private int sequence;
033: private static final int[] NEXT = new int[] { 1, 2, 2 };
034: private byte[][] buffers;
035:
036: private final byte[] FIRST_DATA;
037: private static byte[] HEADER;
038: private static byte[] REPEATING_DATA;
039:
040: static {
041: initialize();
042: }
043:
044: private static void initialize() {
045: try {
046: ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
047: DataOutputStream dout = new DataOutputStream(byteOut);
048: dout.writeShort(ObjectStreamConstants.STREAM_MAGIC);
049: dout.writeShort(ObjectStreamConstants.STREAM_VERSION);
050: HEADER = byteOut.toByteArray();
051:
052: byteOut = new ByteArrayOutputStream();
053: dout = new DataOutputStream(byteOut);
054:
055: dout.writeByte(ObjectStreamConstants.TC_OBJECT);
056: dout.writeByte(ObjectStreamConstants.TC_REFERENCE);
057: dout.writeInt(ObjectStreamConstants.baseWireHandle);
058: REPEATING_DATA = byteOut.toByteArray();
059: } catch (final IOException e) {
060: throw new Error("IOException: " + e.getMessage());
061: }
062:
063: }
064:
065: public MockStream(final Class clazz) {
066: this .pointer = 0;
067: this .sequence = 0;
068: this .data = HEADER;
069:
070: // (byte) TC_OBJECT
071: // (byte) TC_CLASSDESC
072: // (short length)
073: // (byte * className.length)
074: // (long)serialVersionUID
075: // (byte) SC_SERIALIZABLE
076: // (short)0 <fields>
077: // TC_ENDBLOCKDATA
078: // TC_NULL
079: final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
080: final DataOutputStream dout = new DataOutputStream(byteOut);
081: try {
082: dout.writeByte(ObjectStreamConstants.TC_OBJECT);
083: dout.writeByte(ObjectStreamConstants.TC_CLASSDESC);
084: dout.writeUTF(clazz.getName());
085: dout.writeLong(ObjectStreamClass.lookup(clazz)
086: .getSerialVersionUID());
087: dout.writeByte(ObjectStreamConstants.SC_SERIALIZABLE);
088: dout.writeShort((short) 0); // Zero fields
089: dout.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA);
090: dout.writeByte(ObjectStreamConstants.TC_NULL);
091: } catch (final IOException e) {
092: throw new Error("IOException: " + e.getMessage());
093: }
094: this .FIRST_DATA = byteOut.toByteArray();
095: this .buffers = new byte[][] { HEADER, this .FIRST_DATA,
096: REPEATING_DATA };
097: }
098:
099: private void advanceBuffer() {
100: this .pointer = 0;
101: this .sequence = NEXT[this .sequence];
102: this .data = this .buffers[this .sequence];
103: }
104:
105: public int read() throws IOException {
106: final int result = this .data[this .pointer++];
107: if (this .pointer >= this .data.length) {
108: advanceBuffer();
109: }
110:
111: return result;
112: }
113:
114: public int available() throws IOException {
115: return Integer.MAX_VALUE;
116: }
117:
118: public int read(final byte[] b, int off, final int len)
119: throws IOException {
120: int left = len;
121: int remaining = this .data.length - this .pointer;
122:
123: while (remaining <= left) {
124: System.arraycopy(this .data, this .pointer, b, off,
125: remaining);
126: off += remaining;
127: left -= remaining;
128: advanceBuffer();
129: remaining = this .data.length - this .pointer;
130: }
131: if (left > 0) {
132: System.arraycopy(this .data, this .pointer, b, off, left);
133: this .pointer += left;
134: }
135:
136: return len;
137: }
138: }
139:
140: private ObjectInputStream inputStream;
141:
142: public ObjectInputStreamInstantiator(final Class clazz) {
143: if (Serializable.class.isAssignableFrom(clazz)) {
144: try {
145: this .inputStream = new ObjectInputStream(
146: new MockStream(clazz));
147: } catch (final IOException e) {
148: throw new Error("IOException: " + e.getMessage());
149: }
150: } else {
151: throw new ObjenesisException(new NotSerializableException(
152: clazz + " not serializable"));
153: }
154: }
155:
156: public Object newInstance() {
157: try {
158: return this .inputStream.readObject();
159: } catch (final ClassNotFoundException e) {
160: throw new Error("ClassNotFoundException: " + e.getMessage());
161: } catch (final Exception e) {
162: throw new ObjenesisException(e);
163: }
164: }
165: }
|