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/PropertyTokenizer.html#PropertyTokenizer">PropertyTokenizer prop = new PropertyTokenizer(name);
73 if (prop.hasNext()) {
74 MetaClass metaProp = metaClassForProperty(prop.getName());
75 return metaProp.getSetterType(prop.getChildren());
76 } else {
77 return reflector.getSetterType(prop.getName());
78 }
79 }
80
81 public Class<?> getGetterType(String name) {
82 PropertyTokenizer/PropertyTokenizer.html#PropertyTokenizer">PropertyTokenizer prop = new PropertyTokenizer(name);
83 if (prop.hasNext()) {
84 MetaClass metaProp = metaClassForProperty(prop);
85 return metaProp.getGetterType(prop.getChildren());
86 }
87
88 return getGetterType(prop);
89 }
90
91 private MetaClass metaClassForProperty(PropertyTokenizer prop) {
92 Class<?> propType = getGetterType(prop);
93 return MetaClass.forClass(propType, reflectorFactory);
94 }
95
96 private Class<?> getGetterType(PropertyTokenizer prop) {
97 Class<?> type = reflector.getGetterType(prop.getName());
98 if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) {
99 Type returnType = getGenericGetterType(prop.getName());
100 if (returnType instanceof ParameterizedType) {
101 Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
102 if (actualTypeArguments != null && actualTypeArguments.length == 1) {
103 returnType = actualTypeArguments[0];
104 if (returnType instanceof Class) {
105 type = (Class<?>) returnType;
106 } else if (returnType instanceof ParameterizedType) {
107 type = (Class<?>) ((ParameterizedType) returnType).getRawType();
108 }
109 }
110 }
111 }
112 return type;
113 }
114
115 private Type getGenericGetterType(String propertyName) {
116 try {
117 Invoker invoker = reflector.getGetInvoker(propertyName);
118 if (invoker instanceof MethodInvoker) {
119 Field _method = MethodInvoker.class.getDeclaredField("method");
120 _method.setAccessible(true);
121 Method method = (Method) _method.get(invoker);
122 return TypeParameterResolver.resolveReturnType(method, reflector.getType());
123 } else if (invoker instanceof GetFieldInvoker) {
124 Field _field = GetFieldInvoker.class.getDeclaredField("field");
125 _field.setAccessible(true);
126 Field field = (Field) _field.get(invoker);
127 return TypeParameterResolver.resolveFieldType(field, reflector.getType());
128 }
129 } catch (NoSuchFieldException | IllegalAccessException ignored) {
130 }
131 return null;
132 }
133
134 public boolean hasSetter(String name) {
135 PropertyTokenizer/PropertyTokenizer.html#PropertyTokenizer">PropertyTokenizer prop = new PropertyTokenizer(name);
136 if (prop.hasNext()) {
137 if (reflector.hasSetter(prop.getName())) {
138 MetaClass metaProp = metaClassForProperty(prop.getName());
139 return metaProp.hasSetter(prop.getChildren());
140 } else {
141 return false;
142 }
143 } else {
144 return reflector.hasSetter(prop.getName());
145 }
146 }
147
148 public boolean hasGetter(String name) {
149 PropertyTokenizer/PropertyTokenizer.html#PropertyTokenizer">PropertyTokenizer prop = new PropertyTokenizer(name);
150 if (prop.hasNext()) {
151 if (reflector.hasGetter(prop.getName())) {
152 MetaClass metaProp = metaClassForProperty(prop);
153 return metaProp.hasGetter(prop.getChildren());
154 } else {
155 return false;
156 }
157 } else {
158 return reflector.hasGetter(prop.getName());
159 }
160 }
161
162 public Invoker getGetInvoker(String name) {
163 return reflector.getGetInvoker(name);
164 }
165
166 public Invoker getSetInvoker(String name) {
167 return reflector.getSetInvoker(name);
168 }
169
170 private StringBuilder buildProperty(String name, StringBuilder builder) {
171 PropertyTokenizer/PropertyTokenizer.html#PropertyTokenizer">PropertyTokenizer prop = new PropertyTokenizer(name);
172 if (prop.hasNext()) {
173 String propertyName = reflector.findPropertyName(prop.getName());
174 if (propertyName != null) {
175 builder.append(propertyName);
176 builder.append(".");
177 MetaClass metaProp = metaClassForProperty(propertyName);
178 metaProp.buildProperty(prop.getChildren(), builder);
179 }
180 } else {
181 String propertyName = reflector.findPropertyName(name);
182 if (propertyName != null) {
183 builder.append(propertyName);
184 }
185 }
186 return builder;
187 }
188
189 public boolean hasDefaultConstructor() {
190 return reflector.hasDefaultConstructor();
191 }
192
193 }