[英]Creating a custom AbstractProcessor and integrating with Eclipse
[英]Java Reflection: Find method usage in custom AbstractProcessor
我是反思的新手。 有没有办法检测调用特定方法的位置? 例如:
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
}
}
是这样的事情还是我疯了?
正如评论中所提到的,Apache BCEL适合您的问题。 这些库通常特别用于从生成的字节码确定编译时信息,例如方法使用和控制流分析,并且如果不是不可能的话,使用反射检索这些信息是困难的。 如果使用BCEL解决方案,则可能不再需要自定义注释处理器。
但由于您似乎已经在使用自定义注释处理器,因此它的重点是能够处理源文件中的注释。 因此,一种方法是定义标记正在调用的方法的自定义注释,并让自定义处理器读取这些注释以了解哪些类调用哪些方法:
@CallerClass("MyClass.method")
public class Test {
public test() {
MyClass.method();
}
}
在上面的(普通)示例中,自定义CallerClass
注释标记一个类调用括号内注释元素中指定的方法。 注释处理器可以读取此注释并构造调用者信息。
您可以定义自己的机制。 使用Map
存储每个方法的调用者:
public static Map<Method, List<String>> callStack = new HashMap<Method, List<String>>();
public static void registerCaller(Method m)
{
List<String> callers = callStack.get(m);
if (callers == null)
{
callers = new ArrayList<String>();
callStack.put(m, callers);
}
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
callers.add(stackTraceElements[3].getClassName());
}
目标类:
class MyClass
{
public static void method()
{
registerCaller(new Object(){}.getClass().getEnclosingMethod());
// DO SOMETHING
}
}
一些来电课程:
package the.package.of;
class Test
{
public void test()
{
MyClass.method();
}
}
class Foo
{
public void bar()
{
MyClass.method();
}
}
最后,测试:
new Test().test();
new Foo().bar();
Method method = MyClass.class.getDeclaredMethod("method");
for (String clazz : callStack.get(method))
{
System.out.println(clazz);
}
印刷品:
the.package.of.Test
the.package.of.Foo
好吧,如果您使用Eclipse作为IDE,您可以通过“Open Call Hierarchy”功能找到完整的调用层次结构。 这将在任何打开的Eclipse项目中找到您的方法的所有用法。 但是,如果要在运行时以编程方式查找,则需要集成一些库,这些库可以静态分析类路径的字节码以使用您的方法。
您可以在测试方法内获取堆栈跟踪:
public class Test {
public void test() {
System.out.println(getCallerClass());
}
public static String getCallerClass() {
for (StackTraceElement e: Thread.currentThread().getStackTrace()) {
if (!"java.lang.Thread".equals(e.getClassName()) && !e.getClassName().equals(Test.class.getName()))
return e.getClassName();
}
return null;
}
}
是的,如果你真的想要它是可行的。 您可以使用classLoader搜索类路径,并通过所有类文件扫描方法名称。 下面是一个非常简单的例子,表明它是可行的。 在下面的示例中,我找到了在此类中使用的“println”方法的用法。 基本上,您可以将范围从我的示例中的一个文件扩展到所有类文件。
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");
}
}
在我的IDE中,我不得不使用FileInputStream来访问我正在搜索的类文件....但是如果你正在搜索jar文件,那么你可以使用classLoader代替。 你需要机制来搜索所有的类路径......这不是不可能的,但为了简洁,我把它留给了我们。
编辑:这是尝试让它完全工作..搜索类路径中的所有文件为您的方法。
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;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.