• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.dx.mockito;
18 
19 import java.io.ObjectInputStream;
20 import java.io.ObjectStreamClass;
21 import java.lang.reflect.Field;
22 import java.lang.reflect.Method;
23 
24 /**
25  * Do sneaky things to allocate objects without invoking their constructors.
26  * This is like objenesis but it works on Android. Derived from Gson's
27  * UnsafeAllocator.
28  */
29 abstract class UnsafeAllocator {
newInstance(Class<T> c)30     public abstract <T> T newInstance(Class<T> c) throws Exception;
31 
create()32     public static UnsafeAllocator create() {
33         // try JVM
34         // public class Unsafe {
35         //   public Object allocateInstance(Class<?> type);
36         // }
37         try {
38             Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
39             Field f = unsafeClass.getDeclaredField("theUnsafe");
40             f.setAccessible(true);
41             final Object unsafe = f.get(null);
42             final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);
43             return new UnsafeAllocator() {
44                 @Override
45                 @SuppressWarnings("unchecked")
46                 public <T> T newInstance(Class<T> c) throws Exception {
47                     return (T) allocateInstance.invoke(unsafe, c);
48                 }
49             };
50         } catch (Exception ignored) {
51         }
52 
53         // try dalvikvm, pre-gingerbread
54         // public class ObjectInputStream {
55         //   private static native Object newInstance(
56         //     Class<?> instantiationClass, Class<?> constructorClass);
57         // }
58         try {
59             final Method newInstance = ObjectInputStream.class
60                     .getDeclaredMethod("newInstance", Class.class, Class.class);
61             newInstance.setAccessible(true);
62             return new UnsafeAllocator() {
63                 @Override
64                 @SuppressWarnings("unchecked")
65                 public <T> T newInstance(Class<T> c) throws Exception {
66                     return (T) newInstance.invoke(null, c, Object.class);
67                 }
68             };
69         } catch (Exception ignored) {
70         }
71 
72         // try dalvikvm, post-gingerbread
73         // public class ObjectStreamClass {
74         //   private static native int getConstructorId(Class<?> c);
75         //   private static native Object newInstance(Class<?> instantiationClass, int methodId);
76         // }
77         try {
78             Method getConstructorId = ObjectStreamClass.class
79                     .getDeclaredMethod("getConstructorId", Class.class);
80             getConstructorId.setAccessible(true);
81             final int constructorId = (Integer) getConstructorId.invoke(null, Object.class);
82             final Method newInstance = ObjectStreamClass.class
83                     .getDeclaredMethod("newInstance", Class.class, int.class);
84             newInstance.setAccessible(true);
85             return new UnsafeAllocator() {
86                 @Override
87                 @SuppressWarnings("unchecked")
88                 public <T> T newInstance(Class<T> c) throws Exception {
89                     return (T) newInstance.invoke(null, c, constructorId);
90                 }
91             };
92         } catch (Exception ignored) {
93         }
94 
95         // give up
96         return new UnsafeAllocator() {
97             @Override
98             public <T> T newInstance(Class<T> c) {
99                 throw new UnsupportedOperationException("Cannot allocate " + c);
100             }
101         };
102     }
103 }