10

The situation seems to be abnormal, but I was asked to build serializer that will parse an object into string by concatenating results of "get" methods. The values should appear in the same order as their "get" equivalent is declared in source code file.

So, for example, we have

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

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

The result should be:

"value1 - value2"

An not

"value2 - value1"

It can't be done with Class object according to the documentation. But I wonder if I can find this information in "*.class" file or is it lost? If such data exists, maybe, someone knows a ready to use tool for that purpose? If such information can't be found, please, suggest the most professional way of achieving the goal. I thought about adding some kind of custom annotations to the getters of the class that should be serialized.

Lii
  • 11,553
  • 8
  • 64
  • 88
Denis
  • 1,130
  • 3
  • 17
  • 32
  • =) We decided to use annotations. Everything is fine! – Denis Jul 02 '10 at 22:18
  • 1
    Just in case you're interested I answered a very similar question for someone else, it is actually pretty easy (read the comments too): http://stackoverflow.com/questions/12834887/how-to-get-the-line-number-of-a-method/14973713#comment21272750_14973713 – Quaternion Feb 27 '13 at 18:30
  • @Quaternion: Unfortunately, the method body line number approach doesn't work at all for abstract/interface methods. I'm looking for a way to enumerate bean accessor methods of an interface in order. – Trevor Robinson May 24 '13 at 20:42
  • 1
    @Denis: You said that you usesd some annotations. Can you provide a example how you solved this? Iam having the same problem right now. – some_coder Dec 11 '13 at 08:11
  • Inquiring minds want to know: how to annotations tell you the source file order, without you explicitly coding that in the annotation? that seems *really* inconvenient. – Ira Baxter Jul 26 '14 at 17:31
  • What you appear to want is a "canonical" export form, that won't change if somebody switches from Java N to Java M. Why not generate a description of the class content as a sequence of getter names (order doesn't actually matter), and then generate the data dump in the same order? Then a reader can process the values in the original getter provided order, which should be independent of which java version you are running. – Ira Baxter Jul 26 '14 at 17:35
  • Possible duplicate of [Java Reflection: Getting fields and methods in declaration order](https://stackoverflow.com/questions/5001172/java-reflection-getting-fields-and-methods-in-declaration-order) – GotoFinal Jul 24 '19 at 21:44

5 Answers5

3

Although reflection does not anymore (as of java 7 I think) give you the methods in the order in which they appear in the source code, the class file appears to still (as of Java 8) contain the methods in the order in which they appear in the source code.

So, you can parse the class file looking for method names and then sort the methods based on the file offset in which each method was found.

If you want to do it in a less hacky way you can use Javassist, which will give you the line number of each declared method, so you can sort methods by line number.

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
3

If you want that you have to parse the source code, not the byte code.

There are a number of libraries that parse a source file into a node tree, my favorite is the javaparser (hosted at code.google.com), which, in a slightly modified version, is also used by spring roo.

On the usage page you can find some samples. Basically you will want to use a Visitor that listens for MethodDefinitions.

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
1

I don't think the information is retained.

JAXB, for example, has @XmlType(propOrder="field1, field2") where you define the order of the fields when they are serialized to xml. You can implemenet something similar

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • 2
    Actually this information is retained most of the time (default of Eclipse and Sun javac in order to allow lines in stack traces). If it is so, one could parse the LineNumberTables of the class file in question and deduce the order of the methods. Of course this is not very elegant. I think your suggestion is way better. – musiKk Jun 30 '10 at 12:42
  • yes, even if the information is retained, I'd doubt it is reliable – Bozho Jun 30 '10 at 12:56
  • I thought about something like that (annotations). I just wanted to be sure the order of the methods can't be achieved directly from bytecode. "muzikk" your offer seems to be very helpful! I will use debug info if we don't come to an agreement of using annotations. Do you know which document claims of retaining order of the methods? – Denis Jul 01 '10 at 18:59
1

Edit: This works only on concrete classes (the class to inspect has its own .class file). I changed the code below to reflect this. Until diving deeper into the ClassFileAnalyzer library to work with classes directly instead of reading them from a temporary file this limitation exists.

Following approach works for me:

Download and import following libarary ClassFileAnalyzer

Add the following two static methods (Attention! getClussDump() needs a little modification for writing out the class file to a temporary file: I removed my code here because it's very special at this point):

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;
}

Now you can call the sortMethodsBySourceOrder with any List of methods (because sorting arrays is not very comfortable) and you will get the list back sorted.

It works by looking at the class dumps constant pool which in turn can be determined by the library.

Greetz, GHad

GHad
  • 9,611
  • 6
  • 34
  • 40
0

Write your custom annotation to store ordering data, then use Method.getAnnotation(Class annotationClass)

saugata
  • 2,823
  • 1
  • 27
  • 39