【问题标题】:Get declared methods in order they appear in source code按它们在源代码中出现的顺序获取声明的方法
【发布时间】:2011-03-10 01:30:05
【问题描述】:

情况似乎不正常,但我被要求构建序列化程序,通过连接“get”方法的结果将对象解析为字符串。这些值的出现顺序应与其在源代码文件中声明的“get”等效项的顺序相同。

例如,我们有

 Class testBean1{
  public String getValue1(){
   return "value1";
  }

  public String getValue2(){
   return "value2";
  }
 }

结果应该是:

"value1 - value2"

一个不

"value2 - value1"

根据文档,它不能用 Class 对象完成。但我想知道我是否可以在“*.class”文件中找到这些信息,还是丢失了?如果存在此类数据,也许有人知道为此目的准备使用的工具?如果找不到此类信息,请提出最专业的实现目标的方法。我考虑为应该序列化的类的 getter 添加某种自定义注释。

【问题讨论】:

  • =) 我们决定使用注释。一切都很好!
  • 如果您有兴趣,我为其他人回答了一个非常相似的问题,实际上非常简单(也请阅读 cmets):stackoverflow.com/questions/12834887/…
  • @Quaternion:不幸的是,方法体行号方法根本不适用于抽象/接口方法。我正在寻找一种按顺序枚举接口的 bean 访问器方法的方法。
  • @Denis:你说你使用了一些注释。你能举例说明你是如何解决这个问题的吗?我现在也有同样的问题。
  • 有疑问的人想知道:如何通过注释告诉你源文件的顺序,而不需要你在注释中明确编码?这似乎真的不方便。

标签: java reflection


【解决方案1】:

尽管反射不再(我认为从 java 7 开始)按照它们在源代码中出现的顺序为您提供方法,但类文件似乎仍然(从 Java 8 开始)包含按顺序排列的方法它们出现在源代码中。

因此,您可以解析类文件以查找方法名称,然后根据找到每个方法的文件偏移量对方法进行排序。

如果你想以一种不那么老套的方式来做,你可以使用 Javassist,它会给你每个声明的方法的行号,所以你可以按行号对方法进行排序。

【讨论】:

    【解决方案2】:

    编辑:这仅适用于具体类(要检查的类有自己的 .class 文件)。我更改了下面的代码以反映这一点。在深入研究 ClassFileAnalyzer 库以直接使用类而不是从临时文件中读取它们之前,存在此限制。

    以下方法对我有用:

    下载并导入以下库ClassFileAnalyzer

    添加以下两个静态方法(注意!getClussDump() 需要稍作修改才能将类文件写入临时文件:我在这里删除了我的代码,因为此时它非常特殊):

    public static String getClassDump(Class<?> c) throws Exception {
        String classFileName = c.getSimpleName() + ".class";
        URL resource = c.getResource(classFileName);
        if (resource == null) {
            throw new RuntimeException("Works only for concreate classes!");
        }
        String absolutePath = ...; // write to temp file and get absolute path
        ClassFile classFile = new ClassFile(absolutePath);
        classFile.parse();
        Info infos = new Info(classFile, absolutePath);
        StringBuffer infoBuffer = infos.getInfos();
        return infoBuffer.toString();
    }
    
    public static <S extends List<Method>> S sortMethodsBySourceOrder(Class<?> c, S methods) throws Exception {
        String classDump = getClassDump(c);
        int index = classDump.indexOf("constant_pool_count:");
        final String dump = classDump.substring(index);
        Collections.sort(methods, new Comparator<Method>() {
        public int compare(Method o1, Method o2) {
            Integer i1 = Integer.valueOf(dump.indexOf(" " + o1.getName() + lineSeparator));
            Integer i2 = Integer.valueOf(dump.indexOf(" " + o2.getName() + lineSeparator));
            return i1.compareTo(i2);
        }});
        return methods;
    }
    

    现在您可以使用任何方法列表调用 sortMethodsBySourceOrder(因为对数组进行排序不是很舒服),您将得到重新排序的列表。

    它通过查看类转储常量池来工作,而常量池又可以由库确定。

    问候, 加德

    【讨论】:

    • 谢谢!虽然我们决定使用注解,但我以后一定会试试你的代码。
    【解决方案3】:

    如果你想你必须解析源代码,而不是字节码。

    有许多库可以将源文件解析为节点树,我最喜欢的是 javaparser(托管在 code.google.com),在稍作修改的版本中,spring roo 也使用了它.

    the usage page,您可以找到一些示例。基本上你会想要使用一个监听 MethodDefinitions 的访问者。

    【讨论】:

    • Google 与那个 java 解析器无关。
    • 感谢您的建议!但只有编译的类可用。
    【解决方案4】:

    编写自定义注解来存储排序数据,然后使用 Method.getAnnotation(Class annotationClass)

    【讨论】:

      【解决方案5】:

      我认为信息不会被保留。

      例如,JAXB 具有@XmlType(propOrder="field1, field2"),您可以在其中定义字段序列化为 xml 时的顺序。你可以实现类似的东西

      【讨论】:

      • 实际上大部分时间都保留了这些信息(Eclipse 和 Sun javac 的默认设置是为了允许堆栈跟踪中的行)。如果是这样,可以解析相关类文件的 LineNumberTables 并推断方法的顺序。当然,这不是很优雅。我认为你的建议更好。
      • 是的,即使保留信息,我也怀疑它是否可靠
      • 我想到了类似的东西(注释)。我只是想确保不能直接从字节码中实现方法的顺序。 "muzikk" 你的提议似乎很有帮助!如果我们不同意使用注释,我将使用调试信息。你知道哪些文件声称保留了方法的顺序吗?
      猜你喜欢
      • 2017-09-01
      • 2011-06-27
      • 2014-06-17
      • 1970-01-01
      • 2013-05-07
      • 2015-01-10
      • 2020-06-18
      • 2023-04-02
      • 2014-03-07
      相关资源
      最近更新 更多