1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.reflection;
17
18 import java.lang.reflect.Field;
19 import java.lang.reflect.Method;
20 import java.lang.reflect.ParameterizedType;
21 import java.lang.reflect.Type;
22 import java.util.Collection;
23
24 import org.apache.ibatis.reflection.invoker.GetFieldInvoker;
25 import org.apache.ibatis.reflection.invoker.Invoker;
26 import org.apache.ibatis.reflection.invoker.MethodInvoker;
27 import org.apache.ibatis.reflection.property.PropertyTokenizer;
28
29
30
31
32 public class MetaClass {
33
34 private final ReflectorFactory reflectorFactory;
35 private final Reflector reflector;
36
37 private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
38 this.reflectorFactory = reflectorFactory;
39 this.reflector = reflectorFactory.findForClass(type);
40 }
41
42 public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) {
43 return new MetaClass(type, reflectorFactory);
44 }
45
46 public MetaClass metaClassForProperty(String name) {
47 Class<?> propType = reflector.getGetterType(name);
48 return MetaClass.forClass(propType, reflectorFactory);
49 }
50
51 public String findProperty(String name) {
52 StringBuilder prop = buildProperty(name, new StringBuilder());
53 return prop.length() > 0 ? prop.toString() : null;
54 }
55
56 public String findProperty(String name, boolean useCamelCaseMapping) {
57 if (useCamelCaseMapping) {
58 name = name.replace("_", "");
59 }
60 return findProperty(name);
61 }
62
63 public String[] getGetterNames() {
64 return reflector.getGetablePropertyNames();
65 }
66
67 public String[] getSetterNames() {
68 return reflector.getSetablePropertyNames();
69 }
70
71 public Class<?> getSetterType(String name) {
72 PropertyTokenizer prop = new PropertyTokenizer(name);
73 if (prop.hasNext()) {
74 MetaClass metaProp = metaClassForProperty(prop.getName());
75 return metaProp.getSetterType(prop.getChildren());
76 }
77 return reflector.getSetterType(prop.getName());
78 }
79
80 public Class<?> getGetterType(String name) {
81 PropertyTokenizer prop = new PropertyTokenizer(name);
82 if (prop.hasNext()) {
83 MetaClass metaProp = metaClassForProperty(prop);
84 return metaProp.getGetterType(prop.getChildren());
85 }
86
87 return getGetterType(prop);
88 }
89
90 private MetaClass metaClassForProperty(PropertyTokenizer prop) {
91 Class<?> propType = getGetterType(prop);
92 return MetaClass.forClass(propType, reflectorFactory);
93 }
94
95 private Class<?> getGetterType(PropertyTokenizer prop) {
96 Class<?> type = reflector.getGetterType(prop.getName());
97 if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) {
98 Type returnType = getGenericGetterType(prop.getName());
99 if (returnType instanceof ParameterizedType) {
100 Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
101 if (actualTypeArguments != null && actualTypeArguments.length == 1) {
102 returnType = actualTypeArguments[0];
103 if (returnType instanceof Class) {
104 type = (Class<?>) returnType;
105 } else if (returnType instanceof ParameterizedType) {
106 type = (Class<?>) ((ParameterizedType) returnType).getRawType();
107 }
108 }
109 }
110 }
111 return type;
112 }
113
114 private Type getGenericGetterType(String propertyName) {
115 try {
116 Invoker invoker = reflector.getGetInvoker(propertyName);
117 if (invoker instanceof MethodInvoker) {
118 Field declaredMethod = MethodInvoker.class.getDeclaredField("method");
119 declaredMethod.setAccessible(true);
120 Method method = (Method) declaredMethod.get(invoker);
121 return TypeParameterResolver.resolveReturnType(method, reflector.getType());
122 }
123 if (invoker instanceof GetFieldInvoker) {
124 Field declaredField = GetFieldInvoker.class.getDeclaredField("field");
125 declaredField.setAccessible(true);
126 Field field = (Field) declaredField.get(invoker);
127 return TypeParameterResolver.resolveFieldType(field, reflector.getType());
128 }
129 } catch (NoSuchFieldException | IllegalAccessException e) {
130
131 }
132 return null;
133 }
134
135 public boolean hasSetter(String name) {
136 PropertyTokenizer prop = new PropertyTokenizer(name);
137 if (!prop.hasNext()) {
138 return reflector.hasSetter(prop.getName());
139 }
140 if (reflector.hasSetter(prop.getName())) {
141 MetaClass metaProp = metaClassForProperty(prop.getName());
142 return metaProp.hasSetter(prop.getChildren());
143 }
144 return false;
145 }
146
147 public boolean hasGetter(String name) {
148 PropertyTokenizer prop = new PropertyTokenizer(name);
149 if (!prop.hasNext()) {
150 return reflector.hasGetter(prop.getName());
151 }
152 if (reflector.hasGetter(prop.getName())) {
153 MetaClass metaProp = metaClassForProperty(prop);
154 return metaProp.hasGetter(prop.getChildren());
155 }
156 return false;
157 }
158
159 public Invoker getGetInvoker(String name) {
160 return reflector.getGetInvoker(name);
161 }
162
163 public Invoker getSetInvoker(String name) {
164 return reflector.getSetInvoker(name);
165 }
166
167 private StringBuilder buildProperty(String name, StringBuilder builder) {
168 PropertyTokenizer prop = new PropertyTokenizer(name);
169 if (prop.hasNext()) {
170 String propertyName = reflector.findPropertyName(prop.getName());
171 if (propertyName != null) {
172 builder.append(propertyName);
173 builder.append(".");
174 MetaClass metaProp = metaClassForProperty(propertyName);
175 metaProp.buildProperty(prop.getChildren(), builder);
176 }
177 } else {
178 String propertyName = reflector.findPropertyName(name);
179 if (propertyName != null) {
180 builder.append(propertyName);
181 }
182 }
183 return builder;
184 }
185
186 public boolean hasDefaultConstructor() {
187 return reflector.hasDefaultConstructor();
188 }
189
190 }