Java 按声明的方法在源代码中出现的顺序获取它们

Java 按声明的方法在源代码中出现的顺序获取它们,java,reflection,Java,Reflection,这种情况似乎不正常,但我被要求构建序列化程序,通过连接“get”方法的结果将对象解析为字符串。这些值的出现顺序应与其在源代码文件中声明的“get”等效值相同 例如,我们有 Class testBean1{ public String getValue1(){ return "value1"; } public String getValue2(){ return "value2"; } } 结果应该是: "value1 - value2" 不 "value2

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

例如,我们有

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

  public String getValue2(){
   return "value2";
  }
 }
结果应该是:

"value1 - value2"

"value2 - value1"

根据文档,无法使用
Class
对象完成此操作。但是我想知道我是否能在“*.class”文件中找到这些信息,或者它是否丢失了?如果有这样的数据存在,也许有人知道一个随时可用的工具用于此目的?如果找不到这些信息,请建议实现目标的最专业的方法。我考虑过向应该序列化的类的getter添加某种自定义注释。

我认为信息不会被保留


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

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

如果您需要解析源代码,而不是字节码

有许多库可以将源文件解析为节点树,我最喜欢的是(托管在code.google.com上),SpringRoo也使用了这个库,只是稍微修改了一下


你可以在网上找到一些样品。基本上,您需要使用侦听方法定义的访问者。

编辑:这只适用于具体类(要检查的类有自己的.class文件)。为了反映这一点,我修改了下面的代码。在深入到ClassFileAnalyzer库中直接处理类而不是从临时文件中读取类之前,这种限制是存在的。

以下方法对我有效:

下载并导入以下库

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

公共静态字符串getClassDump(类c)引发异常{
字符串classFileName=c.getSimpleName()+“.class”;
URL resource=c.getResource(classFileName);
if(资源==null){
抛出新的RuntimeException(“仅适用于concreate类!”);
}
字符串absolutePath=…;//写入临时文件并获取绝对路径
ClassFile ClassFile=新类文件(绝对路径);
parse();
Info infos=新信息(类文件,绝对路径);
StringBuffer-infoBuffer=infos.getInfos();
返回infoBuffer.toString();
}
公共静态S SortMethodBySourceOrder(类c,S方法)引发异常{
字符串classDump=getClassDump(c);
int index=classDump.indexOf(“常量池计数:”);
最终字符串转储=classDump.substring(索引);
Collections.sort(方法,新的Comparator(){
公共整数比较(方法o1,方法o2){
Integer i1=Integer.valueOf(dump.indexOf(“+o1.getName()+lineSeparator));
Integer i2=Integer.valueOf(dump.indexOf(“+o2.getName()+lineSeparator));
返回i1。比较(i2);
}});
返回方法;
}
现在,您可以使用任何方法列表调用sortMethodsBySourceOrder(因为排序数组不是很舒服),您将重新排序列表

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

格里茨,
GHad

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

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


如果您想以一种不太老套的方式进行,您可以使用Javassist,它将为您提供每个已声明方法的行号,这样您就可以按行号对方法进行排序。

实际上,此信息大部分时间都会被保留(Eclipse和Sun javac的默认设置是为了允许堆栈跟踪中的行)。如果是这样的话,就可以解析所讨论的类文件的LineNumberTables并推断方法的顺序。当然这不是很优雅。我认为你的建议更好。是的,即使信息被保留,我也怀疑它的可靠性。我考虑过类似的事情(注释)。我只是想确定方法的顺序不能直接从字节码实现。“muzikk”你的提议似乎很有帮助!如果我们没有达成使用注释的协议,我将使用调试信息。你知道哪些文档声称保留方法的顺序吗?谷歌与java解析器无关。谢谢你的建议!但是只有编译过的类可用。=)我们决定使用注释。一切都很好!如果你感兴趣,我为其他人回答了一个非常类似的问题,其实很简单(也可以阅读评论):@Quaternion:不幸的是,方法体行号方法对于抽象/接口方法根本不起作用。我正在寻找一种按顺序枚举接口的bean访问器方法的方法。@Denis:你说你使用了一些注释。你能举例说明你是如何解决这个问题的吗?我现在也有同样的问题。好奇的人想知道:注释如何告诉你源文件的顺序,而不需要你在注释中显式地编码?那似乎真的很不方便。谢谢!虽然我们决定使用注释,但稍后我肯定会尝试您的代码。
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;
}