views:

100

answers:

4

Hello,

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.

Waiting for a help, Best Regards!

+1  A: 

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
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
yes, even if the information is retained, I'd doubt it is reliable
Bozho
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
A: 

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

saugata
+2  A: 

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.

seanizer
Google has nothing to do with that java parser.
Kevin Bourrillion
you're right, of course. I updated my answer
seanizer
thanks for suggestion! But only compiled classes are available.
Denis
A: 

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
Thanks! Although we decided to use annotations, I will certainly try your code later.
Denis