2
votes

This question has multiple parts, and will all make sense in the last part:

  1. Is it possible to programmatically list any programmer-defined variables in a Java class at runtime..?

    I recently wrote a utility procedure in VB.Net that lists all the forms in my project by name, so I can pick one to run from a listbox (just for development purposes). With help from elsewhere on StackOverflow, I was able to pin the following bit of code together, and this example is pinned together even more for illustrative purposes...

        System.Reflection.Assembly.GetExecutingAssembly().DefinedTypes(n).BaseType.FullName
    

    Can something similar be done in Java to list variable names..? That being MyInteger, MyString, or MyObject, for example. It'd be like the function behind the "Locals" window in Visual Studio (but I'm using Eclipse for Java).

  2. Somewhere in the past 20 years, in another programming language, I came across a function called Indirect(String varname). It was used to access a primitive variable by name. And the 'varname' parameter could itself be a variable; it didn't have to be a literal. Here's an example showing its use:

    int N1, N2, N3;
    // N1, N2, & N3 are all zero
    for (int i = 1; i < 4; i++){
        Indirect("N" + i.toString) = 100
    }
    // N1, N2, & N3 are now all 100
    

    Does Java have an equivalent to Indirect(), or is there a way to duplicate the same functionality..?

  3. To glue all this together, and the reason for this entire forum post, is that I have the following procedure that I've written for debugging purposes, that I drop into my classes to output variable values in CSV format during development...

    public String listVars(){
        Object input[] = {var1, var2, var3, var4, var5};    // list of vars
        String output = "";                     // output catcher
        int varCount = input.length;            // get the length of the array
        for (int i = 0; i < varCount; i++){     // loop through the array
            output += "\"" + input[i] + "\"";   // surround with quotes, append to output
            if (i < varCount-1){                // if the item NOT the last...
                output += ",";                  // append a comma to it
            }
        }
        return output;                          // return completed output
    }
    
  4. What I would like to do is automate the input to the Object array with code that automatically enumerates the variables, so I don't have to copy & paste them into the function. And I'm assuming that in so doing, they would need to be referred to indirectly once their names are determined, so their values can be accessed in code.

PS - Filtering the variables by scope would be nice, such as 'private", 'super', <classname>, 'public', etc, but I know this may stretch it a bit too far. =-)

2
Java is not a dynamic language. Once you compile to bytecode, you throw away most of the local variable names. So there is no Indirect, and no list of Locals. However, it can see member names of classes at runtime through reflection.Andrew Williamson
Also, it sounds like you just want to see the objects at runtime. You could use a library like JSON, or the upcoming Java REPL project 'kulla'.Andrew Williamson

2 Answers

1
votes
  1. listing class fields/methods at runtime

yes, you can do that, with reflection. see the tutorial here:

for (Field f : getClass().getDeclaredFields()) {
    System.out.println("found " + f);
}
  1. "Indirect" access

yes, using the above mechanism to find the field you wish to altar you can then set its value

Field f = ... //get it from somewhere
f.set(this, "new value");

what you want to achieve sounds very close to the java bean concept. the gist of it is that you keep to a getX()/setX() naming convention for your getter and setter methods, each such pair representing a property called "x" and you can then utilize bean-oriented libraries, such as apache commons beanutils to all all the heavy lifting (that i told you about above) for you, like so:

Employee employee = ...;
String firstName = (String)PropertyUtils.getSimpleProperty(employee, "firstName");
String lastName = (String)PropertyUtils.getSimpleProperty(employee, "lastName");
 ... manipulate the values ...
PropertyUtils.setSimpleProperty(employee, "firstName", firstName);
PropertyUtils.setSimpleProperty(employee, "lastName", lastName);
0
votes

First, all of Java's reflection api can be found under java.lang.reflect package and that the best way to learn that package is probably java's own trails Reflection Trail

TL;DR

1) It seems after some investigation there is a Field.getName() so that would probably serve you well.

2) There is indeed a way to obtain fields (variables) as well as methods and even constructors. [Specific Trail page][3] The way to do that is through the Field class in the reflect package. An example of this is Field foo = myObject.class.getField("fieldName") or class.getDeclaredField("name") the difference being that the declared version explicitly only looks in that object and also gets the private fields as well.

There are s versions as well class.getDeclaredFields() and class.getFields() that return a Field[]. There are also method and constructor versions of all 4 types (declared, regular, and s (array) of both)

3) A lot of information is accessible from access modifiers (private, public etc.) and through Field.toGenericString() or Field.getModifiers() etc.

As for the implementation, it should be along the lines of Field.getDeclaredFields() combined with Field.getName() and Field.get*() where * is the type (int, long, Object etc). If you need fields from super class and you still want to list the privates then you wold need to recursively apply Class.getSuperclass() with Field.getDeclaredFields(). Additionally Field.toGenericString() if you want a nice long detailed string.