1+ package com .litesuits .orm .db .utils ;
2+
3+ import java .io .ObjectInputStream ;
4+ import java .io .ObjectStreamClass ;
5+ import java .lang .reflect .Constructor ;
6+ import java .lang .reflect .Field ;
7+ import java .lang .reflect .InvocationTargetException ;
8+ import java .lang .reflect .Method ;
9+
10+ /**
11+ * Magic that creates instances of arbitrary concrete classes. Derived from Gson's UnsafeAllocator
12+ * and ConstructorConstructor classes.
13+ * Copy from square/moshi project.
14+ * @author Joel Leitch
15+ * @author Jesse Wilson
16+ */
17+ abstract class ClassFactory <T > {
18+ abstract T newInstance () throws
19+ InvocationTargetException , IllegalAccessException , InstantiationException ;
20+
21+ public static <T > ClassFactory <T > get (final Class <?> rawType ) {
22+ // Try to find a no-args constructor. May be any visibility including private.
23+ try {
24+ final Constructor <?> constructor = rawType .getDeclaredConstructor ();
25+ constructor .setAccessible (true );
26+ return new ClassFactory <T >() {
27+ @ SuppressWarnings ("unchecked" ) // T is the same raw type as is requested
28+ @ Override
29+ public T newInstance () throws IllegalAccessException , InvocationTargetException ,
30+ InstantiationException {
31+ Object [] args = null ;
32+ return (T ) constructor .newInstance (args );
33+ }
34+
35+ @ Override
36+ public String toString () {
37+ return rawType .getName ();
38+ }
39+ };
40+ } catch (NoSuchMethodException ignored ) {
41+ // No no-args constructor. Fall back to something more magical...
42+ }
43+
44+ // Try the JVM's Unsafe mechanism.
45+ // public class Unsafe {
46+ // public Object allocateInstance(Class<?> type);
47+ // }
48+ try {
49+ Class <?> unsafeClass = Class .forName ("sun.misc.Unsafe" );
50+ Field f = unsafeClass .getDeclaredField ("theUnsafe" );
51+ f .setAccessible (true );
52+ final Object unsafe = f .get (null );
53+ final Method allocateInstance = unsafeClass .getMethod ("allocateInstance" , Class .class );
54+ return new ClassFactory <T >() {
55+ @ SuppressWarnings ("unchecked" )
56+ @ Override
57+ public T newInstance () throws InvocationTargetException , IllegalAccessException {
58+ return (T ) allocateInstance .invoke (unsafe , rawType );
59+ }
60+
61+ @ Override
62+ public String toString () {
63+ return rawType .getName ();
64+ }
65+ };
66+ } catch (IllegalAccessException e ) {
67+ throw new AssertionError ();
68+ } catch (ClassNotFoundException ignored ) {
69+ // Not the expected version of the Oracle Java library!
70+ } catch (NoSuchMethodException ignore ) {
71+ // Not the expected version of the Oracle Java library!
72+ } catch (NoSuchFieldException ignore ) {
73+ // Not the expected version of the Oracle Java library!
74+ }
75+
76+ // Try (post-Gingerbread) Dalvik/libcore's ObjectStreamClass mechanism.
77+ // public class ObjectStreamClass {
78+ // private static native int getConstructorId(Class<?> c);
79+ // private static native Object newInstance(Class<?> instantiationClass, int methodId);
80+ // }
81+ try {
82+ Method getConstructorId = ObjectStreamClass .class .getDeclaredMethod (
83+ "getConstructorId" , Class .class );
84+ getConstructorId .setAccessible (true );
85+ final int constructorId = (Integer ) getConstructorId .invoke (null , Object .class );
86+ final Method newInstance = ObjectStreamClass .class .getDeclaredMethod ("newInstance" ,
87+ Class .class , int .class );
88+ newInstance .setAccessible (true );
89+ return new ClassFactory <T >() {
90+ @ SuppressWarnings ("unchecked" )
91+ @ Override
92+ public T newInstance () throws InvocationTargetException , IllegalAccessException {
93+ return (T ) newInstance .invoke (null , rawType , constructorId );
94+ }
95+
96+ @ Override
97+ public String toString () {
98+ return rawType .getName ();
99+ }
100+ };
101+ } catch (IllegalAccessException e ) {
102+ throw new AssertionError ();
103+ } catch (InvocationTargetException e ) {
104+ throw new RuntimeException (e );
105+ } catch (NoSuchMethodException ignored ) {
106+ // Not the expected version of Dalvik/libcore!
107+ }
108+
109+ // Try (pre-Gingerbread) Dalvik/libcore's ObjectInputStream mechanism.
110+ // public class ObjectInputStream {
111+ // private static native Object newInstance(
112+ // Class<?> instantiationClass, Class<?> constructorClass);
113+ // }
114+ try {
115+ final Method newInstance = ObjectInputStream .class .getDeclaredMethod (
116+ "newInstance" , Class .class , Class .class );
117+ newInstance .setAccessible (true );
118+ return new ClassFactory <T >() {
119+ @ SuppressWarnings ("unchecked" )
120+ @ Override
121+ public T newInstance () throws InvocationTargetException , IllegalAccessException {
122+ return (T ) newInstance .invoke (null , rawType , Object .class );
123+ }
124+
125+ @ Override
126+ 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+ }
0 commit comments