1
16 package com.squareup.moshi;
17
18 import com.squareup.moshi.internal.Util;
19 import java.io.ObjectInputStream;
20 import java.io.ObjectStreamClass;
21 import java.lang.reflect.Constructor;
22 import java.lang.reflect.Field;
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25
26
33 abstract class ClassFactory<T> {
34 abstract T newInstance() throws
35 InvocationTargetException, IllegalAccessException, InstantiationException;
36
37 public static <T> ClassFactory<T> get(final Class<?> rawType) {
38
39 try {
40 final Constructor<?> constructor = rawType.getDeclaredConstructor();
41 constructor.setAccessible(true);
42 return new ClassFactory<T>() {
43 @SuppressWarnings("unchecked")
44 @Override public T newInstance() throws IllegalAccessException, InvocationTargetException,
45 InstantiationException {
46 Object[] args = null;
47 return (T) constructor.newInstance(args);
48 }
49 @Override public String toString() {
50 return rawType.getName();
51 }
52 };
53 } catch (NoSuchMethodException ignored) {
54
55 }
56
57
58
59
60
61 try {
62 Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
63 Field f = unsafeClass.getDeclaredField("theUnsafe");
64 f.setAccessible(true);
65 final Object unsafe = f.get(null);
66 final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);
67 return new ClassFactory<T>() {
68 @SuppressWarnings("unchecked")
69 @Override public T newInstance() throws InvocationTargetException, IllegalAccessException {
70 return (T) allocateInstance.invoke(unsafe, rawType);
71 }
72 @Override public String toString() {
73 return rawType.getName();
74 }
75 };
76 } catch (IllegalAccessException e) {
77 throw new AssertionError();
78 } catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException ignored) {
79
80 }
81
82
83
84
85
86
87 try {
88 Method getConstructorId = ObjectStreamClass.class.getDeclaredMethod(
89 "getConstructorId", Class.class);
90 getConstructorId.setAccessible(true);
91 final int constructorId = (Integer) getConstructorId.invoke(null, Object.class);
92 final Method newInstance = ObjectStreamClass.class.getDeclaredMethod("newInstance",
93 Class.class, int.class);
94 newInstance.setAccessible(true);
95 return new ClassFactory<T>() {
96 @SuppressWarnings("unchecked")
97 @Override public T newInstance() throws InvocationTargetException, IllegalAccessException {
98 return (T) newInstance.invoke(null, rawType, constructorId);
99 }
100 @Override public String toString() {
101 return rawType.getName();
102 }
103 };
104 } catch (IllegalAccessException e) {
105 throw new AssertionError();
106 } catch (InvocationTargetException e) {
107 throw Util.rethrowCause(e);
108 } catch (NoSuchMethodException ignored) {
109
110 }
111
112
113
114
115
116
117 try {
118 final Method newInstance = ObjectInputStream.class.getDeclaredMethod(
119 "newInstance", Class.class, Class.class);
120 newInstance.setAccessible(true);
121 return new ClassFactory<T>() {
122 @SuppressWarnings("unchecked")
123 @Override public T newInstance() throws InvocationTargetException, IllegalAccessException {
124 return (T) newInstance.invoke(null, rawType, Object.class);
125 }
126 @Override public String toString() {
127 return rawType.getName();
128 }
129 };
130 } catch (Exception ignored) {
131 }
132
133 throw new IllegalArgumentException("cannot construct instances of " + rawType.getName());
134 }
135 }
136