178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson/**
2eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin * Copyright 2006-2017 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;
30eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffinimport org.objenesis.instantiator.annotations.Instantiator;
31eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffinimport org.objenesis.instantiator.annotations.Typology;
3278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
3378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson/**
3478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * Instantiates a class by using a dummy input stream that always feeds data for an empty object of
3578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * the same kind. NOTE: This instantiator may not work properly if the class being instantiated
3678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * defines a "readResolve" method, since it may return objects that have been returned previously
3778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * (i.e., there's no guarantee that the returned object is a new one), or even objects from a
3878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * completely different class.
39eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin *
4078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * @author Leonardo Mesquita
4178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson * @see org.objenesis.instantiator.ObjectInstantiator
4278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson */
43eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin@Instantiator(Typology.SERIALIZATION)
44eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffinpublic class ObjectInputStreamInstantiator<T> implements ObjectInstantiator<T> {
4578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson   private static class MockStream extends InputStream {
4678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
4778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private int pointer;
4878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private byte[] data;
4978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private int sequence;
5078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private static final int[] NEXT = new int[] {1, 2, 2};
5178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private byte[][] buffers;
5278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
5378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private final byte[] FIRST_DATA;
5478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private static byte[] HEADER;
5578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private static byte[] REPEATING_DATA;
5678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
5778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      static {
5878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         initialize();
5978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
6078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
6178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private static void initialize() {
6278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         try {
6378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
6478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            DataOutputStream dout = new DataOutputStream(byteOut);
6578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeShort(ObjectStreamConstants.STREAM_MAGIC);
6678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeShort(ObjectStreamConstants.STREAM_VERSION);
6778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            HEADER = byteOut.toByteArray();
6878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
6978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            byteOut = new ByteArrayOutputStream();
7078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout = new DataOutputStream(byteOut);
7178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
7278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeByte(ObjectStreamConstants.TC_OBJECT);
7378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeByte(ObjectStreamConstants.TC_REFERENCE);
7478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeInt(ObjectStreamConstants.baseWireHandle);
7578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            REPEATING_DATA = byteOut.toByteArray();
7678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
7778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         catch(IOException e) {
7878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            throw new Error("IOException: " + e.getMessage());
7978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
8078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
8178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
8278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
83eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      public MockStream(Class<?> clazz) {
8478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         this.pointer = 0;
8578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         this.sequence = 0;
8678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         this.data = HEADER;
8778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
8878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // (byte) TC_OBJECT
8978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // (byte) TC_CLASSDESC
9078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // (short length)
9178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // (byte * className.length)
9278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // (long)serialVersionUID
9378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // (byte) SC_SERIALIZABLE
9478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // (short)0 <fields>
9578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // TC_ENDBLOCKDATA
9678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         // TC_NULL
9778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
9878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         DataOutputStream dout = new DataOutputStream(byteOut);
9978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         try {
10078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeByte(ObjectStreamConstants.TC_OBJECT);
10178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeByte(ObjectStreamConstants.TC_CLASSDESC);
10278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeUTF(clazz.getName());
10378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeLong(ObjectStreamClass.lookup(clazz).getSerialVersionUID());
10478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeByte(ObjectStreamConstants.SC_SERIALIZABLE);
10578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeShort((short) 0); // Zero fields
10678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA);
10778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            dout.writeByte(ObjectStreamConstants.TC_NULL);
10878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
10978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         catch(IOException e) {
11078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            throw new Error("IOException: " + e.getMessage());
11178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
11278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         this.FIRST_DATA = byteOut.toByteArray();
11378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         buffers = new byte[][] {HEADER, FIRST_DATA, REPEATING_DATA};
11478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
11578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
11678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      private void advanceBuffer() {
11778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         pointer = 0;
11878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         sequence = NEXT[sequence];
11978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         data = buffers[sequence];
12078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
12178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
122eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      @Override
12378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      public int read() throws IOException {
12478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         int result = data[pointer++];
12578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         if(pointer >= data.length) {
12678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            advanceBuffer();
12778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
12878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
12978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         return result;
13078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
13178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
132eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      @Override
13378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      public int available() throws IOException {
13478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         return Integer.MAX_VALUE;
13578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
13678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
137eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      @Override
13878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      public int read(byte[] b, int off, int len) throws IOException {
13978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         int left = len;
14078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         int remaining = data.length - pointer;
14178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
14278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         while(remaining <= left) {
14378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            System.arraycopy(data, pointer, b, off, remaining);
14478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            off += remaining;
14578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            left -= remaining;
14678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            advanceBuffer();
14778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            remaining = data.length - pointer;
14878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
14978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         if(left > 0) {
15078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            System.arraycopy(data, pointer, b, off, left);
15178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            pointer += left;
15278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
15378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
15478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         return len;
15578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
15678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson   }
15778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
15878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson   private ObjectInputStream inputStream;
15978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
160eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   public ObjectInputStreamInstantiator(Class<T> clazz) {
16178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      if(Serializable.class.isAssignableFrom(clazz)) {
16278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         try {
16378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            this.inputStream = new ObjectInputStream(new MockStream(clazz));
16478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
16578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         catch(IOException e) {
16678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson            throw new Error("IOException: " + e.getMessage());
16778c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         }
16878c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
16978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      else {
170eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         throw new ObjenesisException(new NotSerializableException(clazz + " not serializable"));
17178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
17278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson   }
17378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson
174eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   @SuppressWarnings("unchecked")
175eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin   public T newInstance() {
17678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      try {
177eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin         return (T) inputStream.readObject();
178eebfcaffb2d52b214abfdb1c0102395c88c9db54Paul Duffin      }
17978c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      catch(ClassNotFoundException e) {
18078c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         throw new Error("ClassNotFoundException: " + e.getMessage());
18178c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
18278c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      catch(Exception e) {
18378c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson         throw new ObjenesisException(e);
18478c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson      }
18578c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson   }
18678c496fe0fac4c89993109340aec80d1afa3141fIan Parkinson}
187