首页 > 解决方案 > 如何以编程方式查找对方法的所有引用?

问题描述

因此,这不是使用 Eclipse IDE 查找方法引用的方法。

我需要通过代码(Java)找到它们。

背景: 我们有数百个项目,都基于一个共同的项目。多年来,通用项目有一些非常糟糕的代码已被替换。错误代码已被标记为已弃用。

现在,我想删除所有已弃用的代码。但是,我想创建一些代码来迁移我们拥有的所有其他项目。

方法: 现在,对于某些事情,我可以在项目代码中搜索一些关键字(即方法名称)并替换为其他内容。但是,有些方法名称会发生​​冲突,并且进行简单的搜索/替换将不起作用。

我的想法是,如果我有一个不推荐使用的方法: com.foo.bar.SomeClass.someMethod(String)

然后以某种方式找到使用 someMethod(String) 的每个地方,然后我可以用 newMethod(String) 替换那个

我看过一些:

基本上,我想创建一个迁移程序,使迁移到新的通用代码变得简单。我计划使用相同的迁移代码来帮助将项目从 JDK8 迁移到 OpenJDK11。

关于如何实现这一点的想法?

标签: javamigration

解决方案


做一些搜索,我有一些基本代码,但仍然没有 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 Eclipse Reference Image

我不确定要改变什么或从这里去哪里。


推荐阅读