Setting a field value of an object that is a child of another object
I am getting the following exception:
java.lang.IllegalArgumentException: obje开发者_如何学编程ct is not an instance of the class
and I have a pretty good idea of why I am getting it - but I am stuck with finding a solution.
Here is the sample code to explain what I want to do:
public class Car {
private Owner owner;
//Constructor and getter for owner field
}
public class Owner {
private String name;
//Constructor and getter for name field
}
Now what I am attempting to do is: Starting from the Car class, I retrieve the field named "owner" - then I retrieve the field "name" of that object owner which is part of a car. Now I want to read (and later modify, but I already fail with reading) the value of the field "name". The problem: I only have an instance of car, but not of its field "owner" . For clarification purposes: The described process shall work generically - so I wont know the names of the getters, setters, fields and so on.
Here is the code that fails (please let me know if more code is required to clarify the problem):
Car car = new Car();
//Set owner and name property of owner for car
...
Field nameField = resolveDatapath(datapathToFeature, car);
nameField.setAccessible(true);
//Here I fail with the afore mentioned IllegalArgumentException, because
//indeed, I am passing car - not its sub-object "owner" (because as I can see it,
//there is no way for me to generically retrieve the owner object - or is there?)
String value = nameField.get(car).toString();
The above stuff should also work for any "depths" (say I want a field and manipulate it from Object c which is a field of object b, which in turn is a field of object a ...)
Please let me know, if I can further clarify the question - here is the code which retrieves the field (in the above example its the nameField):
private Field resolveDatapath(String path, Object parent) {
String subString = path;
if (!subString.contains("."))
{
//We haven reached the end of the path
return getField(subString, parent.getClass());
}
//We haven't reached the end of the
subString = path.substring(0, path.indexOf("."));
Field field = getField(subString, parent.getClass());
return resolveDatapath(path.substring(path.indexOf(".")+1), field);
}
private Field getField(String name, Class<?> parent) {
Field [] fields = parent.getDeclaredFields();
for(Field f : fields)
{
String current = f.getName();
if(current.equalsIgnoreCase(name))
{
try {
return parent.getDeclaredField(current);
} catch (SecurityException e) {
fail("Not allowed to access field - " + current);
} catch (NoSuchFieldException e) {
fail("No such field exists - " + current);
}
}
}
return null;
}
Thank you very much in advance, best regards, Ready4Android
The Field will only give you fields on a given class. It will no navigate into class and obtain sub fields.
I suggest instead you use a plain get field helper like this
String name = (String) getField(car, datapathToFeature);
Okay thanks to Peter for giving my brain the poke it needed ;) I found the solution and here it is:
I create a DatapathObject which contains the field and the parent object as an object. Before I was compaining, that I cant get an instance of the Owner object which is a field in the Car object. Of course thats utter nonsense as I now figured - my brain was kinda slow here :P .
This code works and makes my unittest pass:
public void testDatapathResolution() throws Exception{
String[] path = datapathToFeature.split("\\.");
assertEquals("Owner", path[0]);
assertEquals("Name", path[1]);
DatapathObject result = resolveDatapath(datapathToFeature, car);
result.getField().setAccessible(true);
Object value = result.getField().get(result.getParent());
assertEquals(car.getOwner().getName(), value.toString());
}
And here is the DatapathObject class:
public class DatapathObject {
private Object parent;
private Field field;
public DatapathObject(Object parent, Field field) {
this.parent = parent;
this.field = field;
}
public Object getParent() {
return parent;
}
public Field getField() {
return field;
}
}
My resolveDatapath method chanded as follows (to accomodate the introduction of the DatapathObject:
private DatapathObject resolveDatapath(String path, Object parent) throws
IllegalArgumentException, IllegalAccessException
{
String subString = path;
if (!subString.contains("."))
{
//We haven reached the end of the path
Field field = getField(subString, parent.getClass());
return new DatapathObject(parent, field);
}
//We haven't reached the end of the
subString = path.substring(0, path.indexOf("."));
Field field = getField(subString, parent.getClass());
field.setAccessible(true);
return resolveDatapath(path.substring(path.indexOf(".")+1),
field.get(parent));
}
Thanks again to Peter - lol I still dont understand your answer and I dont think it was what I was looking for but it provided my brain with the missing spark to find the answer :) !
精彩评论