Wicket和'构造函数调用overridable方法'PMD警告

时间:2011-06-09 10:53:41

标签: java oop wicket pmd

我们通过将大部分构造函数代码移到onInitialize()来避免此PMD警告。但我们是否只是将问题(设计缺陷?)转移到一个不同的地方?

即。我们的onInitialize()只是一个代理构造函数,PMD没有注意到它吗?

当你在构造函数中调用可覆盖的方法时,我们遇到了弹出的类型的问题,但这似乎源于Wicket本身调用了一个(无法找到确切的源代码行,但是{{ 1}},一个可覆盖的方法,当你在构造函数中调用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的JavaDoc:

  
    

注意:此调用的时间不准确,合同是在{@link Component#onBeforeRender()}之前的某个时间调用。

  

3 个答案:

答案 0 :(得分:4)

如果仅从onInitialized()方法内部向容器添加组件,则不会出现此问题。但它无法通过PMD验证,至少不能通过内置规则进行验证。

但我认为这不是设计缺陷。这是一个设计决定。您不能将所有设计都基于静态分析工具和预定义规则。 API可用性也是设计的一个重要方面,有时甚至比设计原则更具相关性。

例如,CQS (Command-Query Separation)原则要求某事的方法(更改状态)不应该返回任何内容,并且返回某些东西的方法不应该没有副作用(改变状态)。

如果这是一个硬规则,则无法实现流畅的接口(更改对象状态的方法,并返回this,允许方法链接)。 Wicket广泛使用它(几乎所有组件操作方法都返回this),这是使用它的乐趣之一。

PMD是一个非常有用的工具。但你必须是工具的主人,而不是它的奴隶。您应该将其警告视为可能的问题,但如果您对自己的设计选择有信心,只需将代码标记为绕过并感到高兴。

答案 1 :(得分:1)

考虑以下课程:

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; 发生的位置。

您认为移动onInitialize()初始化会有所帮助吗?为什么不呢?

{{1}}

根据经验,永远不要从非final类的构造函数中调用非私有方法。事实上,在这种情况下我甚至会触发编译错误。正如您所看到的,此问题与Wicket无关,将初始化移至{{1}}是为了避免此类陷阱。

答案 2 :(得分:0)

  

我们遇到了在构造函数中调用可覆盖方法时弹出的排序问题,但这似乎源于Wicket本身调用一个(无法找到确切的源代码行,但是onInitialize(),一个可覆盖的方法,当你在构造函数中调用add()时,最终会被调用。)

我很确定调用onInitialize()时调用的add(component)方法是要添加的组件的onInitialize()方法(add方法的参数)而不是你正在修建的课程。这应该没问题,因为该组件已经完全构建。