Skip to content

Commit d4a8acf

Browse files
committed
修复实现了 Parcelable 接口的类或除该构造方法之外,没有无参构造方法导致创建实例失败的问题
创建实例参考 moshi 的实现。并对创始实例的对象进行缓存,提升查询效率。
1 parent cf70a7d commit d4a8acf

File tree

2 files changed

+143
-20
lines changed

2 files changed

+143
-20
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
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+
}

library/src/main/java/com/litesuits/orm/db/utils/ClassUtil.java

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
package com.litesuits.orm.db.utils;
22

3-
import android.annotation.TargetApi;
4-
import android.os.Build;
53
import com.litesuits.orm.db.annotation.MapCollection;
64

75
import java.lang.reflect.Array;
8-
import java.lang.reflect.Constructor;
96
import java.lang.reflect.Field;
107
import java.lang.reflect.InvocationTargetException;
11-
import java.util.Arrays;
128
import java.util.Collection;
139
import java.util.Date;
14-
import java.util.List;
10+
import java.util.HashMap;
11+
import java.util.Map;
1512

1613
/**
1714
* 类工具
@@ -20,6 +17,7 @@
2017
* @date 2013-6-10下午8:00:46
2118
*/
2219
public class ClassUtil {
20+
private static final Map<Class, ClassFactory> CLASS_FACTORIES = new HashMap();
2321

2422
/**
2523
* 判断类是否是基础数据类型
@@ -39,22 +37,12 @@ public static boolean isBaseDataType(Class<?> clazz) {
3937
*/
4038
public static <T> T newInstance(Class<T> claxx)
4139
throws IllegalAccessException, InvocationTargetException, InstantiationException {
42-
Constructor<?>[] cons = claxx.getDeclaredConstructors();
43-
for (Constructor<?> c : cons) {
44-
Class[] cls = c.getParameterTypes();
45-
if (cls.length == 0) {
46-
c.setAccessible(true);
47-
return (T) c.newInstance();
48-
} else {
49-
Object[] objs = new Object[cls.length];
50-
for (int i = 0; i < cls.length; i++) {
51-
objs[i] = getDefaultPrimiticeValue(cls[i]);
52-
}
53-
c.setAccessible(true);
54-
return (T) c.newInstance(objs);
55-
}
40+
ClassFactory<T> factory = CLASS_FACTORIES.get(claxx);
41+
if (factory == null) {
42+
factory = ClassFactory.get(claxx);
43+
CLASS_FACTORIES.put(claxx, factory);
5644
}
57-
return null;
45+
return factory.newInstance();
5846
}
5947

6048
public static Object newCollection(Class<?> claxx) throws IllegalAccessException, InstantiationException {

0 commit comments

Comments
 (0)