All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ext.test4j.objenesis.instantiator.basic.ObjectInputStreamInstantiator Maven / Gradle / Ivy

There is a newer version: 2.5.0
Show newest version
/**
 * Copyright 2006-2009 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ext.test4j.objenesis.instantiator.basic;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.NotSerializableException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.io.ObjectStreamConstants;
import java.io.Serializable;

import ext.test4j.objenesis.ObjenesisException;
import ext.test4j.objenesis.instantiator.ObjectInstantiator;

/**
 * Instantiates a class by using a dummy input stream that always feeds data for
 * an empty object of the same kind. NOTE: This instantiator may not work
 * properly if the class being instantiated defines a "readResolve" method,
 * since it may return objects that have been returned previously (i.e., there's
 * no guarantee that the returned object is a new one), or even objects from a
 * completely different class.
 * 
 * @author Leonardo Mesquita
 * @see org.objenesis.instantiator.ObjectInstantiator
 */
@SuppressWarnings("rawtypes")
public class ObjectInputStreamInstantiator implements ObjectInstantiator {
	private static class MockStream extends InputStream {

		private int pointer;
		private byte[] data;
		private int sequence;
		private static final int[] NEXT = new int[] { 1, 2, 2 };
		private byte[][] buffers;

		private final byte[] FIRST_DATA;
		private static byte[] HEADER;
		private static byte[] REPEATING_DATA;

		static {
			initialize();
		}

		private static void initialize() {
			try {
				ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
				DataOutputStream dout = new DataOutputStream(byteOut);
				dout.writeShort(ObjectStreamConstants.STREAM_MAGIC);
				dout.writeShort(ObjectStreamConstants.STREAM_VERSION);
				HEADER = byteOut.toByteArray();

				byteOut = new ByteArrayOutputStream();
				dout = new DataOutputStream(byteOut);

				dout.writeByte(ObjectStreamConstants.TC_OBJECT);
				dout.writeByte(ObjectStreamConstants.TC_REFERENCE);
				dout.writeInt(ObjectStreamConstants.baseWireHandle);
				REPEATING_DATA = byteOut.toByteArray();
			} catch (IOException e) {
				throw new Error("IOException: " + e.getMessage());
			}

		}

		public MockStream(Class clazz) {
			this.pointer = 0;
			this.sequence = 0;
			this.data = HEADER;

			// (byte) TC_OBJECT
			// (byte) TC_CLASSDESC
			// (short length)
			// (byte * className.length)
			// (long)serialVersionUID
			// (byte) SC_SERIALIZABLE
			// (short)0 
			// TC_ENDBLOCKDATA
			// TC_NULL
			ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
			DataOutputStream dout = new DataOutputStream(byteOut);
			try {
				dout.writeByte(ObjectStreamConstants.TC_OBJECT);
				dout.writeByte(ObjectStreamConstants.TC_CLASSDESC);
				dout.writeUTF(clazz.getName());
				dout.writeLong(ObjectStreamClass.lookup(clazz).getSerialVersionUID());
				dout.writeByte(ObjectStreamConstants.SC_SERIALIZABLE);
				dout.writeShort((short) 0); // Zero fields
				dout.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA);
				dout.writeByte(ObjectStreamConstants.TC_NULL);
			} catch (IOException e) {
				throw new Error("IOException: " + e.getMessage());
			}
			this.FIRST_DATA = byteOut.toByteArray();
			buffers = new byte[][] { HEADER, FIRST_DATA, REPEATING_DATA };
		}

		private void advanceBuffer() {
			pointer = 0;
			sequence = NEXT[sequence];
			data = buffers[sequence];
		}

		public int read() throws IOException {
			int result = data[pointer++];
			if (pointer >= data.length) {
				advanceBuffer();
			}

			return result;
		}

		public int available() throws IOException {
			return Integer.MAX_VALUE;
		}

		public int read(byte[] b, int off, int len) throws IOException {
			int left = len;
			int remaining = data.length - pointer;

			while (remaining <= left) {
				System.arraycopy(data, pointer, b, off, remaining);
				off += remaining;
				left -= remaining;
				advanceBuffer();
				remaining = data.length - pointer;
			}
			if (left > 0) {
				System.arraycopy(data, pointer, b, off, left);
				pointer += left;
			}

			return len;
		}
	}

	private ObjectInputStream inputStream;

	public ObjectInputStreamInstantiator(Class clazz) {
		if (Serializable.class.isAssignableFrom(clazz)) {
			try {
				this.inputStream = new ObjectInputStream(new MockStream(clazz));
			} catch (IOException e) {
				throw new Error("IOException: " + e.getMessage());
			}
		} else {
			throw new ObjenesisException(new NotSerializableException(clazz + " not serializable"));
		}
	}

	public Object newInstance() {
		try {
			return inputStream.readObject();
		} catch (ClassNotFoundException e) {
			throw new Error("ClassNotFoundException: " + e.getMessage());
		} catch (Exception e) {
			throw new ObjenesisException(e);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy