Установка значения поля объекта, который является дочерним по отношению к другому объекту - PullRequest
1 голос
/ 18 апреля 2011

Я получаю следующее исключение:

java.lang.IllegalArgumentException: объект не является экземпляром класса

и у меня есть довольно хорошее представление о том, почему я его получаю, но я застрял в поиске решения.

Вот пример кода, объясняющий, что я хочу сделать:

public class Car {
  private Owner owner;

  //Constructor and getter for owner field
}

public class Owner {
  private String name;

  //Constructor and getter for name field
}

Теперь я пытаюсь сделать следующее: начиная с класса Car, я получаю поле с именем «owner», а затем извлекаю поле «name» этого владельца объекта, который является частью автомобиля. Теперь я хочу прочитать (и позже изменить, но у меня уже не получается читать) значение поля «имя». Проблема: у меня есть только экземпляр автомобиля, а не его поле "владелец". Для пояснения: описанный процесс должен работать в общем случае, поэтому я не буду знать имена получателей, установщиков, полей и т. Д.

Вот код, который не работает (пожалуйста, дайте мне знать, если для выяснения проблемы требуется больше кода):

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();

Вышеуказанный материал также должен работать для любых «глубин» (скажем, я хочу поле и манипулировать им из объекта c, который является полем объекта b, который, в свою очередь, является полем объекта a ...)

Пожалуйста, дайте мне знать, если я могу уточнить вопрос - вот код, который извлекает поле (в приведенном выше примере это 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;
}

Большое спасибо заранее, с уважением, Ready4Android

Ответы [ 2 ]

0 голосов
/ 19 апреля 2011

Хорошо, спасибо Питеру за то, что он дал моему мозгу ту подсказку, в которой он нуждался;) Я нашел решение, и вот оно:

Я создаю объект DatapathObject, который содержит поле и родительский объект в качестве объекта.До того, как я начал сочинять, я не могу получить экземпляр объекта Owner, который является полем в объекте Car.Конечно, это полная ерунда, как я теперь понял - мой мозг здесь немного медлителен: P.

Этот код работает и делает мой тестовый проход:

    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());
}

А вот класс DatapathObject:

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;
  } 
}

Мой метод resolDatapath изменился следующим образом (чтобы обеспечить введение объекта 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));
}

Еще раз спасибо Питеру - лол. Я до сих пор не понимаю ваш ответ и не думаю, что онэто было то, что я искал, но это дало моему мозгу недостающую искру, чтобы найти ответ :)!

0 голосов
/ 18 апреля 2011

Поле даст вам поля только для данного класса. Он не будет переходить в класс и получать подполя.

Я предлагаю вместо этого использовать простой помощник get field, как этот

  String name = (String) getField(car, datapathToFeature);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...