What's the bug in this reflection code?
My lack of Java is biting me on the heels again. I have the following member function:
protected void setData(Map<String, String[]> data) {
Class thisClass = this.getClass();
for(Map.Entry<String, String[]> item : data.entrySet()) {
try {
Field field = thisClass.getDeclaredField(item.getKey());
try {
if(field.getType().getName().equals("java.lang.Long")) {
// EXCEPTION HERE!!!
field.setLong(this, Long.valueOf(item.getValue()[0]) );
}...
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} catch (NoSuchFieldException e) {
// Skip this field...
continue;
}
}
}
I keep on getting an IllegalArgumentException, and i don't fully understand why. Can anyone offer some insight?
The function takes a map, which i开发者_StackOverflow社区t iterates, and assigns the values to "this" by checking if the field exists on "this" and if so, attempts to call field.set()
.
setLong(..)
tries to set a primitive value, and your fields is java.lang.Long
. Always use the set(..)
method for non-primitives. For primitives getType().getName()
would return int
, long
, etc.
Initial answer: You need to make the field accessible: field.setAccessible(true)
As per Field.set() docs, you get an IllegalArgumentException if you try to set() a value into a field where the value isn't assignable to the field.
With the following code, I only get illegal ARGUMENT exceptions - no illegal access exceptions:
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class Asdf2 {
private Long long1;
Long long2;
protected Long long3;
private long long4;
Long long5;
protected long long6;
protected void setData(Map<String, String[]> data) {
Class thisClass = this.getClass();
for (Map.Entry<String, String[]> item : data.entrySet()) {
try {
Field field = thisClass.getDeclaredField(item.getKey());
try {
field.setAccessible(true);
if (field.getType().getName().equals("java.lang.Long")) {
field.setLong(this, Long.valueOf(item.getValue()[0]));
} else {
field.set(this, item.getValue()); // EXCEPTION HERE!!!
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
} catch (NoSuchFieldException e) {
// Skip this field...
continue;
}
}
}
@Override
public String toString() {
return "Asdf2["
+ "long1=" + long1
+ ",long2=" + long2
+ ",long3=" + long3
+ ",long4=" + long4
+ ",long5=" + long5
+ ",long6=" + long6
+ "]";
}
public static void main(String[] args) {
Map<String, String[]> data = new HashMap<String, String[]>();
data.put("long1", new String[] { "1" });
data.put("long2", new String[] { "2" });
data.put("long3", new String[] { "3" });
data.put("long4", new String[] { "4" });
data.put("long5", new String[] { "5" });
data.put("long6", new String[] { "6" });
Asdf2 test = new Asdf2();
test.setData(data);
System.out.println(test);
System.out.println("Done!");
}
}
My comments are:
1) If its a Long, you put the first element of the value (which is an array) into that field, but otherwise you put the entire array - that will only work if fields are also string arrays
2) You haven't posted the actual exception you get. It might give more details?
3) You need to give us the "this" class - not just the set method - we need to at least see the field definitions.
Which java version is the one you are using. Remember that autoboxing works over 5.0 version. According to the exception detail it seems that you are trying to assign a Long object value to a long (native) value. You could try this:
field.setLong(this, Long.valueOf(item.getValue()[0]).longValue());
hope this helps.
Use field.set(this,Long.valueOf(item.getValue()[0]));
where item.getValue()[0]
is a long value.
精彩评论