Wicket и предупреждение PMD «конструктор вызывает переопределяемый метод» - PullRequest
2 голосов
/ 09 июня 2011

Мы избегали этого предупреждения PMD, перенося большую часть нашего кода конструктора в onInitialize(). Но мы просто перемещаем проблему (недостаток дизайна?) В другое место?

т.е. наш onInitialize() просто суррогатный конструктор, который не заметил PMD?

У нас есть проблемы такого рода, которые возникают, когда вы вызываете переопределенные методы в конструкторе, но, похоже, это происходит из-за того, что сам Wicket вызывает их (не может найти точную исходную строку, но onInitialize(), переопределяемый метод, в итоге вызывается при вызове add() в конструкторе).

Рад предоставить пример кода, если он поможет.

public class PageA extends WebPage {

    protected SomeBean bean;

    public PageA() {
        add(new Label("foo", "bar"));
        bean = new SomeBean();
    }

}

public class PageB extends PageA {

    public PageB() {
        super();
    }

    @Override
    protected void onInitialize() {
        add(new Label("rofl", bean.getSomeText()));
    }
}

Вы могли бы ожидать, что это будет хорошо, но вызов onInitialize не происходит, если вы думаете, что это так:

При вызове add() на странице поток методов:

MarkupContainer    add()    
MarkupContainer    addedComponent() 
Page               componentAdded()
MarkupContainer    initialize()
Component          fireInitialize()
Component          onInitialize()

Итак, как вы можете видеть, если вы добавляете компонент к WebPage, запускается метод onInitialize(), который является перезаписываемым методом, приводящим к экземплярам приведенного выше нормального кода, создающего NullPointerException s.

Единственное предупреждение, которое вы можете получить, это JavaDoc onInitialize():

ПРИМЕЧАНИЕ. Время этого вызова не точное, договор заключается в том, что он вызывается за некоторое время до {@link Component # onBeforeRender ()}.

Ответы [ 3 ]

4 голосов
/ 09 июня 2011

Если вы добавляете компоненты в контейнер только из его метода onInitialized(), эта проблема не возникнет.Но это не может быть проверено PMD, по крайней мере, по встроенным правилам.

Я не думаю, что это дизайн недостаток , хотя.Это дизайн решение .Вы просто не можете основывать весь свой дизайн на инструментах статического анализа и предопределенных правилах.Удобство использования API также является важным аспектом проектирования, иногда даже более значимым, чем принципы проектирования.

Например, принцип CQS (разделение команд-запросов) требует использования метода, который делает что-то (изменяет состояние) не должно ничего возвращать, а методы, которые возвращают что-то не должно иметь никаких побочных эффектов (изменение состояния).

Если это было жесткое правилоСвободные интерфейсы (методы, которые изменяют состояние объекта и возвращают this, позволяя связывать методы) не могут быть реализованы.Wicket широко использует его (почти все методы манипуляции с компонентами возвращают this), и это одно из преимуществ, которое доставляет удовольствие.

PMD - очень полезный инструмент.Но вы должны быть мастером инструмента, а не его рабом.Вы должны рассматривать его предупреждения как возможные проблемы, но если вы уверены в своем выборе дизайна, просто отметьте код, который нужно обойти, и будьте счастливы.

1 голос
/ 09 июня 2011

Рассмотрим следующий класс:

public class A {

    public A() {
        System.out.println(val().toString());
    }

    protected Integer val() {
        return 0;
    }

}

На первый взгляд все выглядит хорошо, предположим, что val() никогда не должно возвращать null, что имеет место.Теперь B подклассы A:

public class B extends A {

    private final Integer i;

    public B() {
        //super();    //implicit
        i = 1;
    }

    @Override
    protected Integer val() {
        return i;
    }
}

Класс B также хорош с первого взгляда - он возвращает i из val(), который никогда не будет null, поскольку он finalу него инициализируется в конструкторе.Однако создание экземпляра B вызовет NullPointerException.Вы понимаете почему? Подсказка : посмотрите, где происходит неявное super().

Как вы думаете, поможет инициализация перемещения i?Почему бы и нет?

private final Integer i = 1;

Как правило, никогда не вызывайте не приватные методы из конструктора неконечного класса.На самом деле я бы даже вызвал ошибку компиляции в этом случае.Как видите, эта проблема не имеет ничего общего с Wicket, и перемещение инициализации на onInitialize() состоит в том, чтобы избежать таких ловушек.

0 голосов
/ 09 июня 2011

У нас есть проблемы такого рода, которые возникают, когда вы вызываете переопределяемые методы в конструкторе, но, похоже, это происходит из-за того, что сам Wicket вызывает их (не может найти точную исходную строку, но onInitialize (), переопределяемый метод, в итоге вызывается при вызове add () в конструкторе).

Я почти уверен, что метод onInitialize(), который вызывается при вызове add(component), является методом onInitialize() добавляемого компонента (аргумент метода add), а не класса, который вы в настоящее время создаете. , Это должно быть хорошо, так как этот компонент уже полностью построен.

...