178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson/**
278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * Copyright 2006-2013 the original author or authors.
378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson *
478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * Licensed under the Apache License, Version 2.0 (the "License");
578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * you may not use this file except in compliance with the License.
678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * You may obtain a copy of the License at
778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson *
878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson *     http://www.apache.org/licenses/LICENSE-2.0
978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson *
1078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * Unless required by applicable law or agreed to in writing, software
1178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * distributed under the License is distributed on an "AS IS" BASIS,
1278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * See the License for the specific language governing permissions and
1478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * limitations under the License.
1578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson */
1678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinsonpackage org.objenesis.instantiator.basic;
1778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
1878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinsonimport java.io.ByteArrayOutputStream;
1978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinsonimport java.io.DataOutputStream;
2078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinsonimport java.io.IOException;
2178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinsonimport java.io.InputStream;
2278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinsonimport java.io.NotSerializableException;
2378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinsonimport java.io.ObjectInputStream;
2478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinsonimport java.io.ObjectStreamClass;
2578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinsonimport java.io.ObjectStreamConstants;
2678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinsonimport java.io.Serializable;
2778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
2878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinsonimport org.objenesis.ObjenesisException;
2978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinsonimport org.objenesis.instantiator.ObjectInstantiator;
3078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
3178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson/**
3278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * Instantiates a class by using a dummy input stream that always feeds data for an empty object of
3378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * the same kind. NOTE: This instantiator may not work properly if the class being instantiated
3478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * defines a "readResolve" method, since it may return objects that have been returned previously
3578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * (i.e., there's no guarantee that the returned object is a new one), or even objects from a
3678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * completely different class.
3778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson *
3878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * @author Leonardo Mesquita
3978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * @see org.objenesis.instantiator.ObjectInstantiator
4078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson */
4178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinsonpublic class ObjectInputStreamInstantiator implements ObjectInstantiator {
4278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson   private static class MockStream extends InputStream {
4378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
4478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private int pointer;
4578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private byte[] data;
4678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private int sequence;
4778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private static final int[] NEXT = new int[] {1, 2, 2};
4878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private byte[][] buffers;
4978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
5078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private final byte[] FIRST_DATA;
5178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private static byte[] HEADER;
5278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private static byte[] REPEATING_DATA;
5378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
5478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      static {
5578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         initialize();
5678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
5778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
5878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private static void initialize() {
5978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         try {
6078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
6178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            DataOutputStream dout = new DataOutputStream(byteOut);
6278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeShort(ObjectStreamConstants.STREAM_MAGIC);
6378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeShort(ObjectStreamConstants.STREAM_VERSION);
6478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            HEADER = byteOut.toByteArray();
6578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
6678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            byteOut = new ByteArrayOutputStream();
6778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout = new DataOutputStream(byteOut);
6878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
6978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeByte(ObjectStreamConstants.TC_OBJECT);
7078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeByte(ObjectStreamConstants.TC_REFERENCE);
7178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeInt(ObjectStreamConstants.baseWireHandle);
7278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            REPEATING_DATA = byteOut.toByteArray();
7378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
7478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         catch(IOException e) {
7578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            throw new Error("IOException: " + e.getMessage());
7678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
7778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
7878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
7978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
8078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      public MockStream(Class clazz) {
8178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         this.pointer = 0;
8278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         this.sequence = 0;
8378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         this.data = HEADER;
8478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
8578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // (byte) TC_OBJECT
8678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // (byte) TC_CLASSDESC
8778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // (short length)
8878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // (byte * className.length)
8978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // (long)serialVersionUID
9078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // (byte) SC_SERIALIZABLE
9178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // (short)0 <fields>
9278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // TC_ENDBLOCKDATA
9378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // TC_NULL
9478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
9578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         DataOutputStream dout = new DataOutputStream(byteOut);
9678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         try {
9778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeByte(ObjectStreamConstants.TC_OBJECT);
9878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeByte(ObjectStreamConstants.TC_CLASSDESC);
9978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeUTF(clazz.getName());
10078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeLong(ObjectStreamClass.lookup(clazz).getSerialVersionUID());
10178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeByte(ObjectStreamConstants.SC_SERIALIZABLE);
10278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeShort((short) 0); // Zero fields
10378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA);
10478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeByte(ObjectStreamConstants.TC_NULL);
10578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
10678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         catch(IOException e) {
10778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            throw new Error("IOException: " + e.getMessage());
10878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
10978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         this.FIRST_DATA = byteOut.toByteArray();
11078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         buffers = new byte[][] {HEADER, FIRST_DATA, REPEATING_DATA};
11178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
11278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
11378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private void advanceBuffer() {
11478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         pointer = 0;
11578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         sequence = NEXT[sequence];
11678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         data = buffers[sequence];
11778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
11878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
11978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      public int read() throws IOException {
12078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         int result = data[pointer++];
12178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         if(pointer >= data.length) {
12278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            advanceBuffer();
12378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
12478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
12578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         return result;
12678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
12778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
12878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      public int available() throws IOException {
12978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         return Integer.MAX_VALUE;
13078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
13178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
13278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      public int read(byte[] b, int off, int len) throws IOException {
13378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         int left = len;
13478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         int remaining = data.length - pointer;
13578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
13678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         while(remaining <= left) {
13778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            System.arraycopy(data, pointer, b, off, remaining);
13878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            off += remaining;
13978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            left -= remaining;
14078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            advanceBuffer();
14178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            remaining = data.length - pointer;
14278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
14378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         if(left > 0) {
14478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            System.arraycopy(data, pointer, b, off, left);
14578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            pointer += left;
14678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
14778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
14878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         return len;
14978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
15078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson   }
15178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
15278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson   private ObjectInputStream inputStream;
15378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
15478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson   public ObjectInputStreamInstantiator(Class clazz) {
15578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      if(Serializable.class.isAssignableFrom(clazz)) {
15678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         try {
15778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            this.inputStream = new ObjectInputStream(new MockStream(clazz));
15878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
15978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         catch(IOException e) {
16078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            throw new Error("IOException: " + e.getMessage());
16178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
16278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
16378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      else {
16478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson    	  throw new ObjenesisException(new NotSerializableException(clazz+" not serializable"));
16578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
16678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson   }
16778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
16878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson   public Object newInstance() {
16978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      try {
17078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         return inputStream.readObject();
17178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
17278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      catch(ClassNotFoundException e) {
17378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         throw new Error("ClassNotFoundException: " + e.getMessage());
17478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
17578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      catch(Exception e) {
17678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         throw new ObjenesisException(e);
17778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
17878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson   }
17978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson}
180