2

Quick edit: As was pointed out below I should be doing a BFS but I need a point to stop retrieving new fields, which I haven't had time to think about yet. Thanks for all the help!

I'm trying to use Java reflection to recursively get the fields of classes, essentially creating a tree to display

Class
 field1 class
  field1.1 class
  field1.2 class
 field2 class
  field 2.1 class
  field 2.2 class

This is for a recursive decent parser, so I figured a recursive display function would be cool to make. Unfortunately it's crushing me.

Example class Foo, with fields of Class1 and Class2, each of which could have more fields of different classes:

class Assignment extends Statement {
Variable target;
Expression source;
Assignment (Variable t, Expression e) {
    target = t;
    source = e;
}

My recursive method:

private void recurse(Object object){
    System.out.println(object.getClass());
    for (Field field : object.getClass().getDeclaredFields()){
        System.out.println(field.getType());
        System.out.println(field.getName());
        if(!field.getType().isPrimitive() || field.getType() instanceof Class || field.getName() != "clazz"){
            //recurse(field);
        }
    }

The println has been for testing and an example output for Foo would be (without recursion, it seems to work) giving

class Assignment
class Variable
target
class Expression
source

But I can't figure out how to take the Variable class and then get its fields and so on. The field that contains this information gives me a class Field.

Also, I realize I need a point to stop the recursion but stopping at primative fields doesn't seem to work. Any suggestions would be useful and really help me understand the nitty-gritty of what I seem to be flailing around in.

Side note: for the means of this class that this is for I know I can just put a display method in for each class and call those, but I the process of reflection seemed more interesting and possibly reusable.

TLDR: How do I get the class of the actual field contained in a Field?

Sorry if I'm missing anything, first question I've asked.

Thanks for your time!

-Alex

Fatlad
  • 324
  • 5
  • 21

2 Answers2

1

Well, you are describing a graph, and a search algorithm in it.

Your graph is G=(V,E) where V = {all object types } and E = { (u,v) | u has a field of type v }.

You can use BFS to "explore" your graph from a single source, and get all "accessable vertices [types]" from it [the single source].

BFS holds a visited set, and avoids exploring vertices [types] that were already explored, and it [BFS] stops, when there is nothing new to discover [the queue is empty].

The same thing can be done with DFS, but again - you are going to need a visited set, in order to avoid infinite loops when the graph has cycles [for example: in some implementations of composite classes, such as a tree, where each Node contains a Node itself].

amit
  • 175,853
  • 27
  • 231
  • 333
  • Thanks! I tried that initially but completely forgot about it getting distracted fighting with the fields! Thanks again for the help :) – Fatlad Apr 13 '12 at 18:57
  • @user1314060: You are most welcome. Don't forget to [accept](http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) one of the answers [the one you found most useful for you!] when you are done. Good luck with this task! Oh, one more thing: you might also be interested in reading [this post](http://stackoverflow.com/questions/9881710/getting-superinterfaces-in-java) which is different, but shows similar ideas :) – amit Apr 13 '12 at 19:03
  • @corsiKa: (1) The OP is looking for all fields of a class, and then recursively their fields. It is very much a graph, as I described in my notation of `G`, and it can have cycles. [`class Tree { Tree t }`] (2) java has multiple inheritence when it comes to `interface`s. True, you can extend only one class, but you can `implement` multiple `interface`s. – amit Apr 13 '12 at 22:22
  • @amit (1) OP is looking for all fields of all classes. If he hits an interface it will have no fields to toss into the queue. This means only concrete classes will actually enter his queue. All of these will end up at a single point, `java.lang.Object`. Pick the tree up by that root node and let the rest dangle down - there will be no cycles thanks to the visited flag. (2) Interfaces are not multiple inheritance. In fact, interfaces were specifically added to Java to address the fact that Java doesn't have multiple inheritance. – corsiKa Apr 13 '12 at 22:37
  • @corsiKa: Why would they all end up with `Object`? He's not looking for the `super` of each field, he's just looking for all fields. For example: `class Tree { Tree left, right; }`, without maintaining a `visited` set, the `Tree` "vertex" will continiously be expanded, without terminating this branch, since there is an edge `(Tree,Tree)`, since `Tree` is a field of `Tree`. Maybe one of us didn't understand the question correctly. [not negating it was me, I am not a native english speaker] – amit Apr 13 '12 at 22:56
  • @amit strange, I swear I saw a `.getSuperclass` in there somewhere... In that light, yes it is very much a graph. A directed, acyclic graph if constructed properly. – corsiKa Apr 13 '12 at 22:59
  • @corsiKa: Again, why acyclic? In the `Tree` example, `(Tree,Tree)` is an edge in this graph. – amit Apr 13 '12 at 23:02
  • @amit Depending on what you're looking for, but that's going to look very, very messy upon output. Essentially what the OP is creating is a dependency graph, and dependency graphs should be acyclic. That's why I said if constructed properly. – corsiKa Apr 14 '12 at 01:12
0

Because you're recurring right away, you're going to go all the way down to Object on the first field of the top level class before moving on to the next. In other word, you're doing a Depth First Search.

You're looking for an output that's more like a Breadth First Search. This will involve using a queue and adding new classes to the end and popping off the next to process instead of using recursion.

You've managed to get this far so I'm not going to spell the whole thing out for you, I'm sure there's enough here to pick the rest up.

corsiKa
  • 81,495
  • 25
  • 153
  • 204
  • Thanks! I got distracted from doing that originally, seems to happen to me when I program, luckily I kept my queue code and can keep the code from what I've learned about fields. Thanks again for the help! :) – Fatlad Apr 13 '12 at 18:59