My goal is to group classes within a package and subpackages into Map<ClassAnnotationType, List<Class> map. @usage e.g map.get(ClassAnnotationType.RestController)
What I've done:
- Get all classes within a package and subpackages. Stack Overflow's question
ClassAnnotationType
public enum ClassAnnotationType {
RestController,
Service,
Unknown
}
List of Class Annotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface RestController{
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Service {
}
This is how the search tree would work
/**
* .class .class package package
* / \ (first iteration) / \ (second iteration)
* .class .class package .class .class package
* / \ (first iteration) / \ (second iteration)
*/
This is the line of code I wish to change
private Map<Boolean, List<String>> getResources(String packageName) {
InputStream inputStream = ClassLoader.getSystemClassLoader()
.getResourceAsStream(packageName.replaceAll("[.]", "/"));
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(inputStream));
return bufferedReader.lines()
.map(i -> packageName.concat("." + i))
.collect(Collectors.partitioningBy(i -> i.endsWith(".class")));
}
into something like this
.collect(
Collectors.groupingBy(i -> {
for (Annotation annotation : i.getAnnotations()) {
// add the Class to the key.
}
}));
My expected result: Collectors.groupingBy() can add 1 item class Hello into 2 different groups e.g RestController, Service
My actual result: 1 item for 1 group.
Current pre-solution
.collect(i -> {
if (i.isAnnotationPresent(RestController.class)) {
return ClassAnnotationType.RestController;
}
return ClassAnnotationType.Unknown; // i wish not to do this.
});
This created problems:
- 1 class only can exists in 1 group.
- Due to the nature of
ClassLoader.getSystemClassLoader().getResourceAsStream()it will returnclass class packagewithin a package. The current code has to list the tree first and map it into String before type casting it toClassusing theClass.forName()method. In other words, the only viable way is to do it in three steps. a. get all the class within a package and subpackages with recursion to aList<String>b. type cast it toList<Class>c. map it toMap<ClassAnnotationType, List<Class>. - All of the classes need to be mapped into a key, including the class without annotation
return ClassAnnotationType.Unknown