0

I am trying to learn about reflection and obtain fields as follows:

Class<?> inputClass = in.getClass(); 
Field[] classFields = inputClass.getFields();

The code is fine up to this point. Now I want to go through each of the fields, printing their value, so I do:

for (Field f : classFields) {
    System.out.println(f.get(new Object()).toString());
}

with an appropriate try/catch for an IllegalAccessException (omitted for clarity). I have also tried passing in a String here, which also yields the result described below. Every f has a type that is not Object, String, or equal to that of in.

This throws the exception:

Exception in thread "Thread-0" java.lang.IllegalArgumentException: Can not set java.lang.String field TestClass.testField to java.lang.Object
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:55)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
at java.lang.reflect.Field.get(Field.java:372)
at LearningReflection.messageToText(LearningReflection.java:88)
at LearningReflection$1.run(LearningReflection.java:180)

I'm guessing this is because I've passed an instance of Object (or String, when I replaced Object with String), rather than an instance of the particular subclass of Object that the class actually contains. Since I don't know what this will be at compile time, I need to extract information from the field as to the type of the class and instantiate it at runtime to pass to the get() method. Is this guess correct, and if so, how do I go about doing this?

Froskoy
  • 2,967
  • 5
  • 20
  • 21
  • Look at this http://stackoverflow.com/questions/364523/is-there-a-general-backend-library-for-java-reflection for several good libraries on Java reflection. – Uberto Nov 18 '12 at 11:59

2 Answers2

1

The main problem is that you are trying to get the value of a TestClass field on an Object instance. This is a type error. Pass the instance of TestClass to get.

class TestClass {
  public Date d = new Date();

  public static void main(String[] args) throws Exception {
    MainClass.printFieldValues(new TestClass());
  }
}

public class MainClass {
  public static void printFieldValues(Object in) throws Exception {
    for (Field f : in.getClass().getFields())
      System.out.println(f.getName() + ": " + f.get(in));
  }
}

Note that this accesses only the public fields of the class/object.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • But since I don't know what MyClass is at compile time, how do I do this? What is the Java syntax for extracting what the class is from the field and instantiating it at runtime? – Froskoy Nov 18 '12 at 12:05
  • You have the instance `in`, so pass it to `get`. – Marko Topolnik Nov 18 '12 at 12:07
  • All the fields f have different types, that are *not* equal to the type of in, so isn't there still a type error here? – Froskoy Nov 18 '12 at 12:11
  • Froskoy, you are **getting** the field, not **setting** it. If you were setting it, you'd still need `in` plus **another argument**, which is the value to set. – Marko Topolnik Nov 18 '12 at 12:21
  • In my code above, inputClass has been downloaded from a server, and is not equal to the type of TestClass. The type of inputClass is unknown at compile time, so the line final Object in = new TestClass(); is impossible. How do you get around this? All the examples you have provided are for a locally defined version of TestClass. – Froskoy Nov 18 '12 at 12:27
  • Your code doesn't depend in any way on the type of `in`. The first thing it does is **get the class of `in`**. To accentuate this better I have extracted the printing method in my sample code. You can clearly see that `printFieldValues` has no dependency on any particular object type. – Marko Topolnik Nov 18 '12 at 12:30
  • Thanks for continuing to help. However, when I implement it in the way you describe, I get exactly the same exception as in my original post. I am simply doing: final Object in = new ChatClient(); System.out.println(f.get(in)); and this gives exactly the same exception. – Froskoy Nov 18 '12 at 12:34
  • Also, the Java documentation states that: "If the underlying field is static, the class that declared the field is initialized if it has not already been initialized." implying that the code *does* depend on the type of in? – Froskoy Nov 18 '12 at 12:38
  • Please post the exact code that fails for you. I don't believe this is possible. As to initialization, the class is clearly already initialiazed because you are starting out from its **instance**, not the `Class` object itself. – Marko Topolnik Nov 18 '12 at 12:39
  • I've now managed to get it to work using your code. Sorry, I was making a small mistake. Thank you very, very much for your help. – Froskoy Nov 18 '12 at 12:39
0
    Object o=Class.forName(qualifiedClassName).newInstance();

then you can cast o to your class and then call appropriate method. qualifiedClassName is the String representation of your class name like "TestClass"

rai.skumar
  • 10,309
  • 6
  • 39
  • 55