![](/img/trans.png)
[英]How to find all Java method calls and given parameters in a project programmatically?
[英]How to find all references to a method programmatically?
因此,這不是使用 Eclipse IDE 查找方法參考的方法。
我需要通過代碼(Java)找到它們。
背景:我們有數百個項目,都基於一個共同的項目。 多年來,通用項目有一些非常糟糕的代碼已被替換。 錯誤代碼已被標記為已棄用。
現在,我想刪除所有已棄用的代碼。 但是,我想創建一些代碼來遷移我們擁有的所有其他項目。
方法:現在,對於某些事情,我可以在項目代碼中搜索一些關鍵字(即方法名稱)並替換為其他內容。 但是,有些方法名稱會發生沖突,並且進行簡單的搜索/替換將不起作用。
我的想法是,如果我有一個不推薦使用的方法: com.foo.bar.SomeClass.someMethod(String)
然后以某種方式找到使用 someMethod(String) 的每個地方,然后我可以用 newMethod(String) 替換那個
我看過一些:
基本上,我想創建一個遷移程序,使遷移到新的通用代碼變得簡單。 我計划使用相同的遷移代碼來幫助將項目從 JDK8 遷移到 OpenJDK11。
關於如何實現這一點的想法?
您當然可以將 ASM 與 ClassVisitor / MethodVisitor 一起使用來查找對該方法的所有引用。
您只需在ClassVisitor
中覆蓋visitMethod
以返回您自己的MethodVisitor
,並在MethodVisitor
中覆蓋visitMethodInsn
。
在 visitMethodInsn 中,您檢查目標是否是不推薦使用的方法之一,並記錄它的使用位置。 這里有一個例子:
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import static org.objectweb.asm.Opcodes.*;
public class MethodScanner extends ClassVisitor {
private final String fileName;
private MethodScanner(String fileName) {
super(ASM7);
this.fileName = fileName;
}
public static void main(String[] args) throws IOException {
scanJar(new File("path/to/some.jar"));
}
public static void scanJar(File jarFile) throws IOException {
var jf = new JarFile(jarFile);
jf.stream().filter(je -> getFileExtension(je.getName()).equals(".class"))
.forEach(je -> processEntry(jf, je));
}
private static String getFileExtension(String name) {
int idx = name.lastIndexOf(".");
if (idx == -1)
return "";
return name.substring(idx);
}
private static void processEntry(JarFile jf, JarEntry je) {
try {
byte[] bytes = jf.getInputStream(je).readAllBytes();
MethodScanner ms = new MethodScanner(jf.getName() + "!" + je.getName());
ClassReader cr = new ClassReader(bytes);
cr.accept(ms, 0);
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
String[] exceptions) {
return new MethodScannerVisitor(super.visitMethod(access, name, descriptor, signature, exceptions), fileName, name + descriptor);
}
private static class MethodScannerVisitor extends MethodVisitor {
private final String fileName;
private final String methodName;
private MethodScannerVisitor(MethodVisitor parent, String fileName, String methodName) {
super(ASM7, parent);
this.fileName = fileName;
this.methodName = methodName;
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
if (owner.equals("java/lang/Math") && name.equals("random") && descriptor.equals("()D")) {
System.out.println("reference to Math.random() from " + fileName + " in " + methodName);
}
}
}
}
做一些搜索,我有一些基本代碼,但仍然沒有 100%
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class ProjectMigration {
public static void main (String[] args) {
ProjectMigration migration = new ProjectMigration();
try {
migration.migrate();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
private List<DeprecatedClass> getDeprecatedMethods () {
List<DeprecatedClass> deprecatedClasses = new ArrayList<>();
deprecatedClasses.add(
new DeprecatedClass("com.e2open.selenium.api_common.abstractHelpers.SystemInformation",
"isInternetExplorer8", "boolean", ""));
deprecatedClasses.add(
new DeprecatedClass("com.e2open.selenium.api_common.AbstractPage", "radioButtonSelect",
"boolean", "java.lang.String", "java.lang.String"));
return deprecatedClasses;
}
public void migrate ()
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
List<DeprecatedClass> deprecatedClasses = getDeprecatedMethods();
for (DeprecatedClass clazz : deprecatedClasses) {
System.out.println("CLASS: " + clazz.getClazz());
Class c = Class.forName(clazz.getClazz());
analyze(c.newInstance(), clazz);
System.out.println();
}
}
private void analyze (Object object, DeprecatedClass deprecatedClass) {
ClassVisitor cv = new ClassVisitor(Opcodes.ASM5) {
@Override
public MethodVisitor visitMethod (
int access, String name, String desc, String signature, String[] exceptions) {
if (isDeprecatedMethod(deprecatedClass, name, desc)) {
logMethod(name, desc);
return new MethodVisitor(Opcodes.ASM5) {
@Override
public void visitMethodInsn (
int opcode, String owner, String name, String desc, boolean arg4) {
if (owner.contains("e2open")) {
processMethod(owner, name, desc);
}
super.visitMethodInsn(opcode, owner, name, desc, arg4);
}
};
}
return null;
}
};
try {
ClassReader classReader = new ClassReader(object.getClass().getCanonicalName());
classReader.accept(cv, 0);
} catch (IOException e) {
System.err.println("Something went wrong !! " + e.getMessage());
}
}
protected void processMethod (String owner, String name, String desc) {
System.out.println(
"classUsed[" + owner.replace("/", ".") + "]; methodUsed[" + name + "]; methodParameters["
+ desc + "]");
}
protected void logMethod (String name, String desc) {
String returnType = getReturnType(desc);
String paramters = getParamters(desc);
System.out.println(String.format("METHOD: %s %s(%s)", returnType, name, paramters));
}
private String getParamters (String desc) {
String parms = desc.split("\\)")[0];
if (parms.equals("(")) {
return "";
}
parms = parms.substring(2, parms.length());
String[] parmameters = parms.split(";");
StringBuilder paramterString = new StringBuilder();
for (String p : parmameters) {
paramterString.append(p.replaceAll("/", ".")).append(", ");
}
return paramterString.toString().substring(0, paramterString.length() - 2);
}
private String getReturnType (String desc) {
String returnType = desc.split("\\)")[1];
if (returnType.equals("V")) {
return "void";
}
if (returnType.length() == 1) {
return returnType;
}
return returnType.substring(1, returnType.length() - 1).replace("/", ".");
}
private boolean isDeprecatedMethod (
DeprecatedClass deprecatedClass, String method, String parmeters) {
if ((method.equals(deprecatedClass.getMethod()))
&& (parmeters.equals(deprecatedClass.getParameters()))) {
return true;
}
return false;
}
private class DeprecatedClass {
private String clazz;
private String method;
private List<String> parameters;
private String returnType;
public DeprecatedClass() {}
/**
* No paramters and no return type
*
* @param clazzName The class to check. Example: com.e2open.selenium.api_common.AbstractPage
* @param methodName The method name to find references for. Example: clearAllInputFields
*/
public DeprecatedClass(String clazzName, String methodName) {
this.clazz = clazzName;
this.method = methodName;
}
/**
* Use if there is a return type and/or parameters
*
* @param clazzName The class to check. Example: com.e2open.selenium.api_common.AbstractPage
* @param methodName he method name to find references for. Example: findFieldByAttribute
* @param returnType The returned type. Example: org.openqa.selenium.By
* @param parameterValues List of paramters. Example: "java.lang.String", "java.lang.String",
* "java.lang.String"
*/
public DeprecatedClass(String clazzName, String methodName, String returnType,
String... parameterValues) {
this.clazz = clazzName;
this.method = methodName;
setReturnType(returnType);
if (parameterValues != null) {
for (String parm : parameterValues) {
if (StringUtils.isNoneBlank(parm)) {
addParameter(parm);
}
}
}
}
/**
* @return the clazz
*/
public String getClazz () {
return clazz;
}
/**
* @param clazz the clazz to set
*/
public void setClazz (String clazz) {
this.clazz = clazz;
}
/**
* @return the method
*/
public String getMethod () {
return method;
}
/**
* @param method the method to set
*/
public void setMethod (String method) {
this.method = method;
}
/**
* @param returnType the returnType to set
*/
public void setReturnType (String returnType) {
if (returnType != null) {
if ("boolean".equals(returnType)) {
this.returnType = "Z";
} else {
this.returnType = "L" + returnType.replaceAll("\\.", "/") + ";";
}
}
}
/**
* @return the parameters
*/
public String getParameters () {
StringBuilder parms = new StringBuilder();
if (this.parameters == null) {
parms.append("()");
} else {
parms.append("(").append(String.join("", this.parameters)).append(")");
}
if (this.returnType == null) {
parms.append("V");
} else {
parms.append(this.returnType);
}
return parms.toString();
}
/**
* @param parameters the parameters to set
*/
public void addParameter (String parameter) {
if (this.parameters == null) {
this.parameters = new ArrayList<>();
}
this.parameters.add("L" + parameter.replaceAll("\\.", "/") + ";");
}
}
}
我得到的結果是:
CLASS: com.e2open.selenium.api_common.abstractHelpers.SystemInformation
METHOD: Z isInternetExplorer8()
classUsed[com.e2open.selenium.api_common.abstractHelpers.SystemInformation]; methodUsed[getSystemData]; methodParameters[()Lcom/e2open/selenium/api_common/abstractHelpers/SystemInformation$SystemData;]
classUsed[com.e2open.selenium.api_common.browser.BrowserType]; methodUsed[equals]; methodParameters[(Ljava/lang/Object;)Z]
CLASS: com.e2open.selenium.api_common.AbstractPage
METHOD: Z radioButtonSelect(java.lang.String, Ljava.lang.String)
classUsed[com.e2open.selenium.api_common.JLog]; methodUsed[write]; methodParameters[(Ljava/lang/String;)V]
classUsed[com.e2open.selenium.api_common.AbstractPage]; methodUsed[radioButtonGet]; methodParameters[(Ljava/lang/String;Ljava/lang/String;)Lorg/openqa/selenium/WebElement;]
然而,結果並不正確。
如果我采用其中一種方法:com.e2open.selenium.api_common.abstractHelpers.SystemInformation.isInternetExplorer8()
並使用 Eclipse 查找 References,我得到isInternetExplorer8 Eclipse References Image
對於其他方法進行搜索:com.e2open.selenium.api_common.AbstractPage.radioButtonSelect(String, String) radioButtonSelect Z32F7222026696F307878 Image89194DEE89194DEE
我不確定從這里更改什么或從哪里更改 go。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.