Skip to content

Commit e1ada13

Browse files
committed
add reflection lib and clean reflection bugs
1 parent ee425bf commit e1ada13

31 files changed

+3715
-6
lines changed

build.gradle

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ repositories {
1515
dependencies {
1616
compileOnly 'com.google.auto.service:auto-service:1.1.1'
1717
annotationProcessor 'com.google.auto.service:auto-service:1.1.1'
18+
implementation 'org.javassist:javassist:3.30.2-GA'
19+
1820

1921
implementation "org.apache.commons:commons-lang3:3.12.0"
2022
testImplementation "org.apache.commons:commons-lang3:3.12.0"
2123

22-
implementation 'org.reflections:reflections:0.10.2'
2324
}
2425

2526
test {
@@ -41,7 +42,7 @@ tasks.register('javadocJar', Jar) {
4142
// mavenJava(MavenPublication) {
4243
// groupId = 'ru.objectsfill'
4344
// artifactId = 'objects-fill-processor'
44-
// version = "0.1.2"
45+
// version = "0.1.3"
4546
// from components.java
4647
// }
4748
// }
@@ -57,7 +58,7 @@ publishing {
5758
artifact javadocJar
5859
artifactId = "objects-fill-processor"
5960
groupId = "ru.objectsfill"
60-
version = "0.1.2"
61+
version = "0.1.3"
6162
from(components["java"])
6263
pom {
6364
packaging 'jar'

src/main/java/ru/objectsfill/utils/ScanningForClassUtils.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
package ru.objectsfill.utils;
22

3-
import org.reflections.Reflections;
43
import ru.objectsfill.annotation_processor.exceptions.FillException;
4+
import ru.objectsfill.utils.reflection.Reflections;
55

66
import java.lang.annotation.Annotation;
77
import java.lang.reflect.InvocationTargetException;
88
import java.util.List;
99
import java.util.Set;
1010

11-
import static org.reflections.scanners.Scanners.SubTypes;
12-
import static org.reflections.scanners.Scanners.TypesAnnotated;
11+
import static ru.objectsfill.utils.reflection.scanners.Scanners.SubTypes;
12+
import static ru.objectsfill.utils.reflection.scanners.Scanners.TypesAnnotated;
13+
1314
/**
1415
* Utility class for scanning classes and retrieving annotated instances or implementations of interfaces.
1516
*/
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package ru.objectsfill.utils.reflection;
2+
3+
4+
import ru.objectsfill.utils.reflection.scanners.Scanner;
5+
import ru.objectsfill.utils.reflection.util.ConfigurationBuilder;
6+
7+
import java.net.URL;
8+
import java.util.Map;
9+
import java.util.Set;
10+
import java.util.function.Predicate;
11+
12+
/**
13+
* Configuration is used to create a configured instance of {@link Reflections}
14+
* <p>it is preferred to use {@link ConfigurationBuilder}
15+
*/
16+
public interface Configuration {
17+
/** the scanner instances used for indexing metadata. defaults to {@code SubTypes} and {@code TypesAnnotated}. */
18+
Set<Scanner> getScanners();
19+
20+
/** the urls to be scanned. required. */
21+
Set<URL> getUrls();
22+
23+
/** the fully qualified name filter used to filter types to be scanned. defaults to accept all inputs (if null). */
24+
Predicate<String> getInputsFilter();
25+
26+
/** scan urls in parallel. defaults to true. */
27+
boolean isParallel();
28+
29+
/** optional class loaders used for resolving types. */
30+
ClassLoader[] getClassLoaders();
31+
32+
/** if true (default), expand super types after scanning, for super types that were not scanned.
33+
* <p>see {@link Reflections#expandSuperTypes(Map, Map)}*/
34+
boolean shouldExpandSuperTypes();
35+
}
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
package ru.objectsfill.utils.reflection;
2+
3+
4+
import ru.objectsfill.utils.reflection.util.ClasspathHelper;
5+
import ru.objectsfill.utils.reflection.util.QueryFunction;
6+
import ru.objectsfill.utils.reflection.util.ReflectionUtilsPredicates;
7+
import ru.objectsfill.utils.reflection.util.UtilQueryBuilder;
8+
9+
import java.lang.annotation.Annotation;
10+
import java.lang.reflect.AnnotatedElement;
11+
import java.lang.reflect.Constructor;
12+
import java.lang.reflect.Field;
13+
import java.lang.reflect.Method;
14+
import java.lang.reflect.Proxy;
15+
import java.net.URL;
16+
import java.util.Arrays;
17+
import java.util.Collections;
18+
import java.util.HashSet;
19+
import java.util.LinkedHashSet;
20+
import java.util.List;
21+
import java.util.Map;
22+
import java.util.Set;
23+
import java.util.function.Predicate;
24+
import java.util.stream.Collectors;
25+
import java.util.stream.Stream;
26+
27+
import static java.util.stream.Collectors.toList;
28+
29+
/**
30+
* utils for querying java reflection meta types
31+
* <p>see {@link #SuperTypes}, {@link #Annotations}, {@link #AnnotationTypes}, {@link #Methods}, {@link #Constructors} and {@link #Fields}.
32+
* <pre>{@code
33+
* Set<Class<?>> supertypes = get(SuperTypes.of(type))
34+
* Set<Annotation> annotations = get(Annotations.of(type))
35+
* }</pre>
36+
* <p>generally, apply {@link #get(QueryFunction)} on {@link QueryFunction} created by {@link UtilQueryBuilder}, and optionally use the functional methods in QueryFunction.
37+
* <pre>{@code get(Methods.of(type)
38+
* .filter(withPublic().and(withPrefix("get")).and(withParameterCount(0)))
39+
* .as(Method.class)
40+
* .map(m -> ...))
41+
* }</pre>
42+
* <p>or (previously), use {@code getAllXXX(type/s, withYYY)} methods:
43+
* <pre>{@code getAllSuperTypes(), getAllFields(), getAllMethods(), getAllConstructors() }
44+
* </pre>
45+
* <p>
46+
* some predicates included here:
47+
* <ul>
48+
* <li>{@link #withPublic()}
49+
* <li>{@link #withParametersCount(int)}}
50+
* <li>{@link #withAnnotation(Annotation)}
51+
* <li>{@link #withParameters(Class[])}
52+
* <li>{@link #withModifier(int)}
53+
* <li>{@link #withReturnType(Class)}
54+
* </ul>
55+
* <pre>{@code
56+
* import static org.reflections.ReflectionUtils.*;
57+
*
58+
* Set<Method> getters =
59+
* get(Methods(classes)
60+
* .filter(withModifier(Modifier.PUBLIC).and(withPrefix("get")).and(withParametersCount(0)));
61+
*
62+
* get(Annotations.of(method)
63+
* .filter(withAnnotation())
64+
* .map(annotation -> Methods.of(annotation)
65+
* .map(method -> )))))
66+
* .stream()...
67+
* }</pre>
68+
* */
69+
@SuppressWarnings({"unchecked", "rawtypes"})
70+
public abstract class ReflectionUtils extends ReflectionUtilsPredicates {
71+
72+
/** get type elements {@code <T>} by applying {@link QueryFunction} <pre>{@code get(SuperTypes.of(type))}</pre> */
73+
public static <C, T> Set<T> get(QueryFunction<C, T> function) {
74+
return function.apply(null);
75+
}
76+
77+
/** get type elements {@code <T>} by applying {@link QueryFunction} and {@code predicates} */
78+
public static <T> Set<T> get(QueryFunction<Store, T> queryFunction, Predicate<? super T>... predicates) {
79+
return get(queryFunction.filter(Arrays.stream((Predicate[]) predicates).reduce(t -> true, Predicate::and)));
80+
}
81+
82+
private static final List<String> objectMethodNames =
83+
Arrays.asList("equals", "hashCode", "toString", "wait", "notify", "notifyAll");
84+
85+
/** predicate to filter out {@code Object} methods */
86+
public static final Predicate<Method> notObjectMethod = m -> !objectMethodNames.contains(m.getName());
87+
88+
/** query super class <pre>{@code get(SuperClass.of(element)) -> Set<Class<?>>}</pre>
89+
* <p>see also {@link ReflectionUtils#SuperTypes}, {@link ReflectionUtils#Interfaces} */
90+
public static final UtilQueryBuilder<Class<?>, Class<?>> SuperClass =
91+
element -> ctx -> {
92+
Class<?> superclass = element.getSuperclass();
93+
return superclass != null && !superclass.equals(Object.class) ? Collections.singleton(superclass) : Collections.emptySet();
94+
};
95+
96+
/** query interfaces <pre>{@code get(Interfaces.of(element)) -> Set<Class<?>>}</pre> */
97+
public static final UtilQueryBuilder<Class<?>, Class<?>> Interfaces =
98+
element -> ctx -> Stream.of(element.getInterfaces()).collect(Collectors.toCollection(LinkedHashSet::new));
99+
100+
/** query super classes and interfaces including element <pre>{@code get(SuperTypes.of(element)) -> Set<Class<?>> }</pre> */
101+
public static final UtilQueryBuilder<Class<?>, Class<?>> SuperTypes =
102+
new UtilQueryBuilder<Class<?>, Class<?>>() {
103+
@Override
104+
public QueryFunction<Store, Class<?>> get(Class<?> element) {
105+
return SuperClass.get(element).add(Interfaces.get(element));
106+
}
107+
108+
@Override
109+
public QueryFunction<Store, Class<?>> of(Class<?> element) {
110+
return QueryFunction.<Store, Class<?>>single(element).getAll(SuperTypes::get);
111+
}
112+
};
113+
114+
/** query annotations <pre>{@code get(Annotation.of(element)) -> Set<Annotation> }</pre> */
115+
public static final UtilQueryBuilder<AnnotatedElement, Annotation> Annotations =
116+
new UtilQueryBuilder<AnnotatedElement, Annotation>() {
117+
@Override
118+
public QueryFunction<Store, Annotation> get(AnnotatedElement element) {
119+
return ctx -> Arrays.stream(element.getAnnotations()).collect(Collectors.toCollection(LinkedHashSet::new));
120+
}
121+
122+
@Override
123+
public QueryFunction<Store, Annotation> of(AnnotatedElement element) {
124+
return ReflectionUtils.extendType().get(element).getAll(Annotations::get, Annotation::annotationType);
125+
}
126+
};
127+
128+
/** query annotation types <pre>{@code get(AnnotationTypes.of(element)) -> Set<Class<? extends Annotation>> }</pre> */
129+
public static final UtilQueryBuilder<AnnotatedElement, Class<? extends Annotation>> AnnotationTypes =
130+
new UtilQueryBuilder<AnnotatedElement, Class<? extends Annotation>>() {
131+
@Override
132+
public QueryFunction<Store, Class<? extends Annotation>> get(AnnotatedElement element) {
133+
return Annotations.get(element).map(Annotation::annotationType);
134+
}
135+
136+
@Override
137+
public QueryFunction<Store, Class<? extends Annotation>> of(AnnotatedElement element) {
138+
return ReflectionUtils.extendType().get(element).getAll(AnnotationTypes::get, a -> a);
139+
}
140+
};
141+
142+
/** query methods <pre>{@code get(Methods.of(type)) -> Set<Method>}</pre> */
143+
public static final UtilQueryBuilder<Class<?>, Method> Methods =
144+
element -> ctx -> Arrays.stream(element.getDeclaredMethods()).filter(notObjectMethod).collect(Collectors.toCollection(LinkedHashSet::new));
145+
146+
/** query constructors <pre>{@code get(Constructors.of(type)) -> Set<Constructor> }</pre> */
147+
public static final UtilQueryBuilder<Class<?>, Constructor> Constructors =
148+
element -> ctx -> Arrays.<Constructor>stream(element.getDeclaredConstructors()).collect(Collectors.toCollection(LinkedHashSet::new));
149+
150+
/** query fields <pre>{@code get(Fields.of(type)) -> Set<Field> }</pre> */
151+
public static final UtilQueryBuilder<Class<?>, Field> Fields =
152+
element -> ctx -> Arrays.stream(element.getDeclaredFields()).collect(Collectors.toCollection(LinkedHashSet::new));
153+
154+
/** query url resources using {@link ClassLoader#getResources(String)} <pre>{@code get(Resources.with(name)) -> Set<URL> }</pre> */
155+
public static final UtilQueryBuilder<String, URL> Resources =
156+
element -> ctx -> new HashSet<>(ClasspathHelper.forResource(element));
157+
158+
public static <T extends AnnotatedElement> UtilQueryBuilder<AnnotatedElement, T> extendType() {
159+
return element -> {
160+
if (element instanceof Class && !((Class<?>) element).isAnnotation()) {
161+
QueryFunction<Store, Class<?>> single = QueryFunction.single((Class<?>) element);
162+
return (QueryFunction<Store, T>) single.add(single.getAll(SuperTypes::get));
163+
} else {
164+
return QueryFunction.single((T) element);
165+
}
166+
};
167+
}
168+
169+
/** get all annotations of given {@code type}, up the super class hierarchy, optionally filtered by {@code predicates}
170+
* <p>marked for removal, use instead {@code get(Annotations.of())} */
171+
public static <T extends AnnotatedElement> Set<Annotation> getAllAnnotations(T type, Predicate<Annotation>... predicates) {
172+
return get(Annotations.of(type), predicates);
173+
}
174+
175+
/** get all super types of given {@code type}, including, optionally filtered by {@code predicates} */
176+
public static Set<Class<?>> getAllSuperTypes(final Class<?> type, Predicate<? super Class<?>>... predicates) {
177+
Predicate<? super Class<?>>[] filter = predicates == null || predicates.length == 0 ? new Predicate[]{t -> !Object.class.equals(t)} : predicates;
178+
return get(SuperTypes.of(type), filter);
179+
}
180+
181+
/** get the immediate supertype and interfaces of the given {@code type}
182+
* <p>marked for removal, use instead {@code get(SuperTypes.get())} */
183+
public static Set<Class<?>> getSuperTypes(Class<?> type) {
184+
return get(SuperTypes.get(type));
185+
}
186+
187+
/** get all methods of given {@code type}, up the super class hierarchy, optionally filtered by {@code predicates}
188+
* <p>marked for removal, use instead {@code get(Methods.of())} */
189+
public static Set<Method> getAllMethods(final Class<?> type, Predicate<? super Method>... predicates) {
190+
return get(Methods.of(type), predicates);
191+
}
192+
193+
/** get methods of given {@code type}, optionally filtered by {@code predicates}
194+
* <p>marked for removal, use instead {@code get(Methods.get())} */
195+
public static Set<Method> getMethods(Class<?> t, Predicate<? super Method>... predicates) {
196+
return get(Methods.get(t), predicates);
197+
}
198+
199+
/** get all constructors of given {@code type}, up the super class hierarchy, optionally filtered by {@code predicates}
200+
* <p>marked for removal, use instead {@code get(Constructors.of())} */
201+
public static Set<Constructor> getAllConstructors(final Class<?> type, Predicate<? super Constructor>... predicates) {
202+
return get(Constructors.of(type), predicates);
203+
}
204+
205+
/** get constructors of given {@code type}, optionally filtered by {@code predicates}
206+
* <p>marked for removal, use instead {@code get(Constructors.get())} */
207+
public static Set<Constructor> getConstructors(Class<?> t, Predicate<? super Constructor>... predicates) {
208+
return get(Constructors.get(t), predicates);
209+
}
210+
211+
/** get all fields of given {@code type}, up the super class hierarchy, optionally filtered by {@code predicates}
212+
* <p>marked for removal, use instead {@code get(Fields.of())} */
213+
public static Set<Field> getAllFields(final Class<?> type, Predicate<? super Field>... predicates) {
214+
return get(Fields.of(type), predicates);
215+
}
216+
217+
/** get fields of given {@code type}, optionally filtered by {@code predicates}
218+
* <p>marked for removal, use instead {@code get(Fields.get())} */
219+
public static Set<Field> getFields(Class<?> type, Predicate<? super Field>... predicates) {
220+
return get(Fields.get(type), predicates);
221+
}
222+
223+
/** get annotations of given {@code type}, optionally honorInherited, optionally filtered by {@code predicates}
224+
* <p>marked for removal, use instead {@code get(Annotations.get())} */
225+
public static <T extends AnnotatedElement> Set<Annotation> getAnnotations(T type, Predicate<Annotation>... predicates) {
226+
return get(Annotations.get(type), predicates);
227+
}
228+
229+
/** map {@code annotation} to hash map of member values recursively <pre>{@code Annotations.of(type).map(ReflectionUtils::toMap)} </pre>*/
230+
public static Map<String, Object> toMap(Annotation annotation) {
231+
return get(Methods.of(annotation.annotationType())
232+
.filter(notObjectMethod.and(withParametersCount(0))))
233+
.stream()
234+
.collect(Collectors.toMap(Method::getName, m -> {
235+
Object v1 = invoke(m, annotation);
236+
return v1.getClass().isArray() && v1.getClass().getComponentType().isAnnotation() ?
237+
Stream.of((Annotation[]) v1).map(ReflectionUtils::toMap).collect(toList()) : v1;
238+
}));
239+
}
240+
241+
/** map {@code annotation} and {@code annotatedElement} to hash map of member values
242+
* <pre>{@code Annotations.of(type).map(a -> toMap(type, a))} </pre>*/
243+
public static Map<String, Object> toMap(Annotation annotation, AnnotatedElement element) {
244+
Map<String, Object> map = toMap(annotation);
245+
if (element != null) map.put("annotatedElement", element);
246+
return map;
247+
}
248+
249+
/** create new annotation proxy with member values from the given {@code map} <pre>{@code toAnnotation(Map.of("annotationType", annotationType, "value", ""))}</pre> */
250+
public static Annotation toAnnotation(Map<String, Object> map) {
251+
return toAnnotation(map, (Class<? extends Annotation>) map.get("annotationType"));
252+
}
253+
254+
/** create new annotation proxy with member values from the given {@code map} and member values from the given {@code map}
255+
* <pre>{@code toAnnotation(Map.of("value", ""), annotationType)}</pre> */
256+
public static <T extends Annotation> T toAnnotation(Map<String, Object> map, Class<T> annotationType) {
257+
return (T) Proxy.newProxyInstance(annotationType.getClassLoader(), new Class<?>[]{annotationType},
258+
(proxy, method, args) -> notObjectMethod.test(method) ? map.get(method.getName()) : method.invoke(map));
259+
}
260+
261+
/** invoke the given {@code method} with {@code args}, return either the result or an exception if occurred */
262+
public static Object invoke(Method method, Object obj, Object... args) {
263+
try {
264+
return method.invoke(obj, args);
265+
} catch (Exception e) {
266+
return e;
267+
}
268+
}
269+
}

0 commit comments

Comments
 (0)