Java Reflection / Generic - PullRequest
       18

Java Reflection / Generic

1 голос
/ 16 ноября 2010

Учитывая следующие три класса, как я могу использовать рефлексию для вызова функции инициализации для родительского (ых) класса (ов), а затем для подкласса:

public class Test {

    public static void main(String[] args) {
        ExtendedElement ee = new ExtendedElement();
        initialize(ee);
     }

    public static void initialize(Element element) {
        System.out.println(element.getClass());
        initialize(element.getClass());
    }

    public static void initialize(Class clazz) {
        System.out.println(clazz.getClass());
    }
}

public class Element {
    protected String value;
    public String getValue() { return value; }
    public void setValue(String value) { this.value = value; }
}

public class ExtendedElement extends Element {
    protected String extendedValue;
    public void setExtendedValue(String extendedValue) {
        this.extendedValue = extendedValue;
    }
    public String getExtendedValue() { return extendedValue; }
}

Я не совсем уверен в том, как параметризироватьФункция initialize в классе Test, поскольку параметр clazz является необработанным типом.

Что мне по сути нужно, так это вызвать инициализацию иерархии классов, если то, что я передаю в initialize, относится к подклассу Element.

Примерно так:

public void initialize(Class clazz) { 
    if (Element.class.isInstance(clazz.getClass().getSuperclass()) {
         initialize(clazz.getClass().getSuperclass());
    }
    //Work to call initialize function 
}

Редактировать 1:

Не могу ли я по-разному параметризовать вышеуказанную псевдофункцию, чтобы сохранить тип объекта, а затем вызвать нужную мне функциюto?

То, что я пытаюсь сделать, - это избежать переопределения одного и того же метода для каждого из моих классов и разрешить некоторое наследование для моих Page Selenium 2 Page Objects.Что мне нужно сделать, так это уметь проанализировать суперкласс (ы) моего «я» и инициализировать каждое из моих полей WebElement перед запуском тестов в этих полях.

Они вводятся пружиной и для дальнейшегоусложняю вещи, которые я позволяю писать тесты на языке Spring Expression.Я лениво загружаю свои бины и использую интерфейс InitializingBean, чтобы попытаться инициализировать мои WebElements до их использования, чтобы избежать NPE.

Мне пришлось обернуть WebElements пользовательским объектом, чтобы я мог внедрить стратегии размещенияиспользование Spring (мы используем много частей, но у них разные идентификаторы / имена классов в зависимости от того, где они используются в приложении; это было сделано до того, как я сюда попал, и не будет изменено в это время, несмотря на мои аргументы в пользу согласованности),Например, у нас есть виджет даты, который имеет разные детализации, иногда нам нужен только месяц, иногда месяц и год и т. Д. Было бы хорошо, если бы я мог использовать абстрактный класс и разбить эти общие черты до их наименьшего общего знаменателяи простираться оттуда.Для этого мне нужно уметь выполнять следующие действия в базовом классе:

public abstract class PageObject implements InitializingBean {
    ...
    public void afterPropertiesSet() {
        //Pass in concrete impl we are working with - this allows me to initialize properly
        initializeWebElements(this.getClass());
    }
    ...
    public void initializeWebElements(Class clazz) {
        //This does not grab inherited fields, which also need to be initialized
        for (Field field : clazz.getDeclaredFields()) {
            if (WidgetElement.class == field.getType()) {
                Method getWidgetElement = clazz.getDeclaredMethod("get" +
                    StringUtils.capitalize(field.getName()), new Class [] {});
                    WidgetElement element = 
                      (WidgetElement) getWidgetElement.invoke(this, new Object [] {});
                    element.initElement();
    }
}

Ответы [ 3 ]

2 голосов
/ 16 ноября 2010

Вы не можете вызвать метод на определенном уровне. Единственное, у вас есть доступ к ключевому слову super внутри самого класса.

Чтобы сделать это, вам нужно вызвать super.initialize() внутри каждого подкласса, а затем просто вызвать его с помощью отражения.

Это не C ++, где вы можете вызывать определенный метод на определенном уровне иерархии наследования.

0 голосов
/ 16 ноября 2010

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

public abstract class PageObject implements InitializingBean {
...
public void afterPropertiesSet() {
    Class clazz = this.getClass();
    do {
        initializeElements(clazz);
        clazz = clazz.getSuperclass();
    } while (clazz != null);
}
0 голосов
/ 16 ноября 2010

Я не совсем уверен, как параметризовать функцию инициализации в классе Test, поскольку параметр clazz является необработанным типом.

Ничто в вашем примере не требует использования параметра универсального типа, поэтому объявите его как Class<?>.

Я не понимаю, что ваши методы инициализации действительно пытаются сделать, но есть ряд проблем:

Похоже, у вас есть один initialize метод, который принимает экземпляр (Element) в качестве аргумента, и другой, который принимает Class объект в качестве аргумента. Это действительно яблоки и апельсины ... и вам нужно объяснить, что вы пытаетесь сделать.

Ваша попытка усовершенствовать метод содержит следующее:

Element.class.isInstance(clazz.getClass().getSuperclass())

Это никогда не будет иметь значение true, поскольку он спрашивает, является ли какой-либо объект Class экземпляром класса Element. (Более того, clazz.getClass().getSuperclass() фактически будет таким же, как java.lang.Object.class. Класс Class объекта равен java.lang.Class, а его суперкласс java.lang.Object).

Но я не могу понять, как это должно быть, потому что вы не можете четко описать, чего пытаетесь достичь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...