1 package pl.matsuo.core.util;
2
3 import com.google.common.base.Joiner;
4 import org.springframework.core.ResolvableType;
5 import pl.matsuo.core.util.function.Failure;
6 import pl.matsuo.core.util.function.Success;
7 import pl.matsuo.core.util.function.Try;
8
9 import java.lang.reflect.AccessibleObject;
10 import java.lang.reflect.AnnotatedElement;
11 import java.lang.reflect.Field;
12 import java.lang.reflect.Method;
13 import java.util.ArrayList;
14 import java.util.List;
15
16 import static com.google.common.collect.Lists.*;
17 import static java.util.Arrays.asList;
18 import static org.springframework.util.StringUtils.*;
19
20
21 @SuppressWarnings("unchecked")
22 public class ReflectUtil {
23
24
25 public static <X> Class<X> resolveType(Class<?> clazz, Class<?> superClazz, int index) {
26 return (Class<X>) ResolvableType.forClass(clazz).as(superClazz).resolveGeneric(index);
27 }
28
29
30 interface EFunction<T, R> {
31 R apply(T t) throws Exception;
32 }
33
34
35 interface EBiFunction<T, U, R> {
36 R apply(T t, U u) throws Exception;
37 }
38
39
40 private static <E extends AccessibleObject> Try<Object> accessMember(Object object, String fieldName,
41 EFunction<String, E> memberGetter, EBiFunction<E, Object, Object> valueGetter) {
42 try {
43 E member = memberGetter.apply(fieldName);
44 try {
45 member.setAccessible(true);
46 return new Success<>(valueGetter.apply(member, object));
47 } finally {
48 member.setAccessible(false);
49 }
50 } catch (Exception e) {}
51
52 return new Failure<>();
53 }
54
55
56 protected static <E> Try<Object> getValue(Object object, String fieldName, Class clazz) {
57 if (!clazz.equals(Object.class)) {
58 return ReflectUtil.<Field>accessMember(object, fieldName, clazz::getDeclaredField, Field::get).ifFailure(
59 () -> ReflectUtil.<Method>accessMember(object, "get" + capitalize(fieldName), clazz::getDeclaredMethod, Method::invoke)
60 ).ifFailure(() -> getValue(object, fieldName, clazz.getSuperclass()));
61 }
62
63 throw new RuntimeException("No such property/getter in class ");
64 }
65
66
67 public static <E> E getValue(Object object, String fieldName) {
68 return (E) getValue(object, fieldName, object.getClass()).get();
69 }
70
71
72
73
74
75 protected static <E> Class<E> getExactPropertyType(List<Class> classes, String exactFieldName) {
76 for (Class clazz : classes) {
77 Class<E> propertyType = getExactPropertyType(clazz, exactFieldName);
78 if (propertyType != null) {
79 return propertyType;
80 }
81 }
82
83 return null;
84 }
85
86
87
88
89
90 protected static <E> Class<E> getExactPropertyType(final Class<?> clazz, String exactFieldName) {
91 if (clazz == null || clazz.equals(Object.class)) {
92 return null;
93 }
94
95
96 try {
97 return (Class<E>) clazz.getDeclaredField(exactFieldName).getType();
98 } catch (Exception e) {}
99
100
101 try {
102 return (Class<E>) clazz.getDeclaredMethod("get" + capitalize(exactFieldName)).getReturnType();
103 } catch (Exception e) {}
104
105
106 List<Class> classes = new ArrayList<>();
107 if (clazz.getSuperclass() != null) {
108 classes.add(clazz.getSuperclass());
109 }
110 classes.addAll(asList(clazz.getInterfaces()));
111
112
113 return getExactPropertyType(classes, exactFieldName);
114 }
115
116
117
118
119
120 public static <E> Class<E> getPropertyType(final Class<?> clazz, String fieldName) {
121 Class<?> exactType = clazz;
122 for (String fieldPart : fieldName.split("[.]")) {
123 exactType = getExactPropertyType(exactType, fieldPart);
124
125 if (exactType == null) {
126 throw new RuntimeException("No such property/getter in class " + clazz.getSimpleName() + " for " + fieldName);
127 }
128 }
129
130 if (exactType == null) {
131 throw new RuntimeException("No such property/getter in class" + clazz.getSimpleName() + " for " + fieldName);
132 } else {
133 return (Class<E>) exactType;
134 }
135 }
136
137
138
139
140
141 protected static AnnotatedElement getExactAnnotatedElement(List<Class> classes, String exactFieldName) {
142 for (Class clazz : classes) {
143 AnnotatedElement annotatedElement = getExactAnnoatedElement(clazz, exactFieldName);
144 if (annotatedElement != null) {
145 return annotatedElement;
146 }
147 }
148
149 return null;
150 }
151
152
153
154
155
156 protected static AnnotatedElement getExactAnnoatedElement(final Class<?> clazz, String exactFieldName) {
157 if (clazz == null || clazz.equals(Object.class)) {
158 return null;
159 }
160
161
162 try {
163 return clazz.getDeclaredField(exactFieldName);
164 } catch (Exception e) {}
165
166 try {
167 return clazz.getDeclaredMethod("get" + capitalize(exactFieldName));
168 } catch (Exception e) {}
169
170
171 List<Class> classes = new ArrayList<>();
172 if (clazz.getSuperclass() != null) {
173 classes.add(clazz.getSuperclass());
174 }
175 classes.addAll(asList(clazz.getInterfaces()));
176
177
178 return getExactAnnotatedElement(classes, exactFieldName);
179 }
180
181
182 public static AnnotatedElement getAnnoatedElement(Class<?> clazz, String fieldName) {
183 String[] splitted = fieldName.split("[.]");
184 List<String> prefix = newArrayList(splitted);
185 String lastElement = prefix.remove(prefix.size() - 1);
186
187
188 if (!prefix.isEmpty()) {
189 clazz = getPropertyType(clazz, Joiner.on(".").join(prefix));
190 }
191
192 return getExactAnnoatedElement(clazz, lastElement);
193 }
194
195
196 public static <E> E invoke(Object target, String methodName, Object ... args) {
197 for (Method method : target.getClass().getMethods()) {
198 if (method.getName().equals(methodName)) {
199 try {
200 return (E) method.invoke(target, args);
201 } catch (Exception e) {
202 throw new RuntimeException("Exception invoking method " + methodName, e);
203 }
204 }
205 }
206
207 throw new RuntimeException("Method " + methodName + " not found");
208 }
209
210
211 public static String fieldName(String methodName) {
212 return uncapitalize(methodName.substring(3));
213 }
214 }
215