Java reflection: finding method usage in custom abstractprocessor
I am a novice reflection Is there any way to detect where a particular method is called? For example:
public class MyClass { public static void method(){ //DO SOMETHING } } public class Test { public test(){ MyClass.method(); } } public class MyProcessor extends AbstractProcessor { public boolean process(Set<? extends TypeElement> annotations,RoundEnvironment roundEnv) { Method method = MyClass.class.getDeclaredMethod("method"); Class classWhereMethodIsInvoked = obtainClassWhereMethodIsInvoked(method); } public Class obtainClassWhereMethodIsInvoked(Method method) { //here I want to search one class that invoke that method,in this case Test.class } }
Is that possible, or am I crazy?
Solution
Yes, if you really want it to work, you can use classloader to search the classpath and scan the method name through all class files The following is a very simple example to illustrate its feasibility In the following example, I find that the "println" method is used in this class Essentially, you can extend the scope of one file in the example to all class files
public class SearchClasses { /** * @param args the command line arguments */ public static void main(String[] args) throws FileNotFoundException { // InputStream is = SearchClasses.class.getClassLoader().getResourceAsStream("resources.SearchClasses.class"); InputStream is = new FileInputStream(new File("build/classes/resources/SearchClasses.class")); boolean found = false; Scanner scanner = new Scanner(is); while (scanner.hasNext()) { if (scanner.nextLine().contains("println")) { System.out.print("println found"); found = true; break; } } if (!found) { System.out.print("println NOT found"); } } public static void testMethod() { System.out.println("testing"); } }
In my IDE, I have to use FileInputStream to access the class file I am searching for However, if you are searching for jar files, you can use classloader You need a mechanism to search all Classpaths... It's not impossible, but I'll stay for simplicity
Editor: This is trying to make it work completely Search all files in the classpath for your method
public class SearchClasses { /** * @param args the command line arguments * @throws java.io.FileNotFoundException */ public static void main(String[] args) throws FileNotFoundException,IOException { printAllFileWithMethod("println"); } public static void printAllFileWithMethod(String methodName) throws FileNotFoundException,IOException { Enumeration<URL> roots = SearchClasses.class.getClassLoader().getResources(""); List<File> allClassFiles = new ArrayList<>(); while (roots.hasMoreElements()) { File root = new File(roots.nextElement().getPath()); allClassFiles.addAll(getFilesInDirectoryWithSuffix(root,"class")); } for (File classFile : allClassFiles) { InputStream is = new FileInputStream(classFile); boolean found = false; Scanner scanner = new Scanner(is); while (scanner.hasNext()) { if (scanner.nextLine().contains(methodName)) { System.out.print(methodName + " found in " + classFile.getName() + "\n"); found = true; break; } } } } public static void testMethod() { System.out.println("testing"); } static List<File> getFilesInDirectoryWithSuffix(File dir,String suffix) { List<File> foundFiles = new ArrayList<>(); if (!dir.isDirectory()) { return foundFiles; } for (File file : dir.listFiles()) { if (file.isDirectory()) { foundFiles.addAll(getFilesInDirectoryWithSuffix(file,suffix)); } else { String name = file.getName(); if (name.endsWith(suffix)) { foundFiles.add(file); } } } return foundFiles; } }