0

我目前正在测试在罐子中提供给我们的 api。我正在尝试获取我们已触及或至少我们的源代码引用的 jar 方法和对象的“覆盖范围”或列表。

我们拥有或将拥有的是“这里是 API 列表”的文本格式

我们需要交叉引用我们自己的应用程序,以确保我们涵盖了列出的 API。

...

这是一个简化的示例... 下面我列出了 jar 中可用的外部代码示例,以及我们使用这些 API 的代码。

-- EXTERNAL_USE_CLASS -- 用我们需要覆盖的公共 API 模拟外部 JAR

package external_api;

public class EXTERNAL_USE_CLASS {
    String myString;
    Integer myInteger;
    Boolean has_ran;
    public EXTERNAL_USE_CLASS() {
        myString = "initial_string";
        myInteger = 4;
        has_ran = false;
    }
    public String getMyString() {
        return myString;
    }
    public void setMyString(String myString) {
        this.myString = myString;
    }
    public Integer getMyInteger() {
        return myInteger;
    }
    public void setMyInteger(Integer myInteger) {
        this.myInteger = myInteger;
    }
    public Boolean getHas_ran() {
        return has_ran;
    }
    public void setHas_ran(Boolean has_ran) {
        this.has_ran = has_ran;
    }
}

我的项目会将上述内容作为 jar 导入并将其添加到构建路径中。我的代码将执行的操作是这样的:

UseExtJar -- 使用外部 jars 对象/方法模拟我们的测试应用程序

import external_api.EXTERNAL_USE_CLASS;

public class UseExtJar {
    static EXTERNAL_USE_CLASS u = new EXTERNAL_USE_CLASS();

    //below is callable via a CLI interface test APP.
    public static void test_basics() {
        Boolean hasRan = u.getHas_ran();
        Integer getInt = u.getMyInteger();
        String getString = u.getMyString();
        System.out.println("u.getHas_ran()"+hasRan);
        System.out.println("u.getMyInteger()"+getInt);
        System.out.println("u.getMyString()"+getString);
    }
}

我有兴趣公开的是外部 Jar 触及的所有 API。

(即这些行)

    Boolean hasRan = u.getHas_ran();
    Integer getInt = u.getMyInteger();
    String getString = u.getMyString();

如果可能的话......我希望能够打印出一些报告,大意是说

您的对象方法 'test_basics' 使用了以下 api:
--external_api.EXTERNAL_USE_CLASS.getHas_ran()
--external_api.EXTERNAL_USE_CLASS.getMyInteger() --external_api.EXTERNAL_USE_CLASS.getMyString()

我必须通过进入我的测试类并在 Eclipse 中右键单击并说“复制限定名称”来获得上述名称。

如果我们必须为 1,000 个 API 执行此操作,这将是一种痛苦……我只是想出了某种方法可以在逻辑上打印出跟踪。

可能我只是不知道正确的谷歌搜索词,这是一个常见的简单任务。

非常感谢任何帮助/指针。

4

3 回答 3

1

如果您知道类的名称以获取有关它的信息,则可以使用反射解决部分问题。您可以打印甚至练习课堂上的方法

import java.lang.reflect.*;

public class DumpMethods { 

  public static void main(String args[])
  {
     try {
        Class c = Class.forName("MyClassName");
        Method m[] = c.getDeclaredMethods();
        for (int i = 0; i < m.length; i++)
        System.out.println(m[i].toString());
     }
     catch (Throwable e) {
        System.err.println(e);
     }
  }
}

这是一个初学者的教程

使用一些库代码来减轻你的一些负担对你来说并不是一件可怕的事情。

不幸的是,分析 jar 的内容并不是那么简单。一旦 jar 的类被加载到 jar 类的概念中就消失了。默认的类加载器只使用包名作为标识唯一类并决定它是否存在于类加载器中的键。因此,您甚至无法真正遍历包中的类,更不用说 jar 的内容了。

为此,您可以创建一个自定义类加载器来分析 jar 并在它从类路径中获取信息时记录信息。

于 2012-09-01T00:38:15.297 回答
0

当您必须为使用的每个 API 类编写一个模拟类时

System.out.println(MyMockedClass.class.getCanonicalName());

获取您正在模拟的类的限定名称。

像这样的东西

Object doMethod(String name){
    try {
        Method method = u.getClass().getDeclaredMethod(name);
        System.out.println("called: " + name);
        try {
            return (String)method.invoke(this);
        } catch (IllegalArgumentException e) {
            return false;
        } catch (IllegalAccessException e) {
            return false;
        } catch (InvocationTargetException e) {
            return false;
        }
    } catch (NoSuchMethodException e) {
        return false;
    }
}

可以给你一种调用和打印你调用的每个方法的方法。

对于使用参数调用的方法,它会变得更加困难。

于 2012-09-01T00:55:21.060 回答
0

谢谢。

我按照您的建议从反射开始,然后转向 ASM,因为我正在使用字节码。


我从引用 ASM 和反射的 2 个链接中提取了我的引用

Java:从 JAR 文件中的类文件中获取方法存根的简单方法?反射?

如何找到在 Java 中调用给定方法的所有方法?


我的解决方案基本上分两步解决了问题

1.从external-jar中读取所有的target-methods

通过 ASM,读入所有满足类路径 (com.my.class.object.*) 和一些 opt-code 过滤器(非私有、非抽象等)的公共类/方法对象,并附加所有满足过滤到存储类/方法的对象列表。

2. foreach 目标方法,检查它是否存在于我们的源代码中。

对于找到的每个目标类/方法,就像上面提供的链接一样,我可以检查位置,并使用行/文件名等打印所有出现。

于 2012-09-01T11:28:03.927 回答