1
16
17 package com.google.gson.internal;
18
19 import java.io.ObjectInputStream;
20 import java.io.ObjectStreamClass;
21 import java.lang.reflect.Field;
22 import java.lang.reflect.Method;
23 import java.lang.reflect.Modifier;
24
25
31 public abstract class UnsafeAllocator {
32 public abstract <T> T newInstance(Class<T> c) throws Exception;
33
34 public static UnsafeAllocator create() {
35
36
37
38
39 try {
40 Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
41 Field f = unsafeClass.getDeclaredField("theUnsafe");
42 f.setAccessible(true);
43 final Object unsafe = f.get(null);
44 final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);
45 return new UnsafeAllocator() {
46 @Override
47 @SuppressWarnings("unchecked")
48 public <T> T newInstance(Class<T> c) throws Exception {
49 assertInstantiable(c);
50 return (T) allocateInstance.invoke(unsafe, c);
51 }
52 };
53 } catch (Exception ignored) {
54 }
55
56
57
58
59
60
61 try {
62 Method getConstructorId = ObjectStreamClass.class
63 .getDeclaredMethod("getConstructorId", Class.class);
64 getConstructorId.setAccessible(true);
65 final int constructorId = (Integer) getConstructorId.invoke(null, Object.class);
66 final Method newInstance = ObjectStreamClass.class
67 .getDeclaredMethod("newInstance", Class.class, int.class);
68 newInstance.setAccessible(true);
69 return new UnsafeAllocator() {
70 @Override
71 @SuppressWarnings("unchecked")
72 public <T> T newInstance(Class<T> c) throws Exception {
73 assertInstantiable(c);
74 return (T) newInstance.invoke(null, c, constructorId);
75 }
76 };
77 } catch (Exception ignored) {
78 }
79
80
81
82
83
84
85 try {
86 final Method newInstance = ObjectInputStream.class
87 .getDeclaredMethod("newInstance", Class.class, Class.class);
88 newInstance.setAccessible(true);
89 return new UnsafeAllocator() {
90 @Override
91 @SuppressWarnings("unchecked")
92 public <T> T newInstance(Class<T> c) throws Exception {
93 assertInstantiable(c);
94 return (T) newInstance.invoke(null, c, Object.class);
95 }
96 };
97 } catch (Exception ignored) {
98 }
99
100
101 return new UnsafeAllocator() {
102 @Override
103 public <T> T newInstance(Class<T> c) {
104 throw new UnsupportedOperationException("Cannot allocate " + c);
105 }
106 };
107 }
108
109
114 static void assertInstantiable(Class<?> c) {
115 int modifiers = c.getModifiers();
116 if (Modifier.isInterface(modifiers)) {
117 throw new UnsupportedOperationException("Interface can't be instantiated! Interface name: " + c.getName());
118 }
119 if (Modifier.isAbstract(modifiers)) {
120 throw new UnsupportedOperationException("Abstract class can't be instantiated! Class name: " + c.getName());
121 }
122 }
123 }
124