Search code examples
javagenericstreewicketvisitor-pattern

Java Wicket (6.19) IVisitor argument passing


Problem

I've been looking around the tutorial from wicket-util-6.19 source, samples library and so forth but did not find an answer to this question. This question is about what kind of parameters (specialization) I can use with an IVisitor.

Spoiler : I know how to have the code to work, I just would like to know why I cannot do the way I want it to.

I have a NestedTree. If you are familiar with wicket-6 NestedTree you may know that the tree is composed of Node whose models is the object you declared your tree with. So it is composed of Node<MyObjectType> (the tree is more complex than that - this is just to exemplify).

Visiting

I want to traverse the tree with a visitor and return the MyObjectType object backing the Node based on a PropertyEn (an enum, but could be a number or anything).

This is how I would write the visit:

private MyObjectType findNode(final PropertyEn propertyEn) {
    return myNestedTree.visitChildren(new IVisitor<Node<MyObjectType>, MyObjectType>() {

        @Override
        public void component(Node<MyObjectType> object, IVisit<MyObjectType> visit) {
            if ( object.getModelObject().getPropertyEn == propertyEn ) {
                visit.stop(object.getModelObject());
            }
        }
    });

There is a problem with generic in the use of the first IVisitor generic argument Node<MyObjectType> object

...Cannot instantiate from arguments because actual and formal arguments lists differ in length...

To make it work

This would compile and possibly work but requires unchecked casting and reflexion :

private MyObjectType findNode(final PropertyEn propertyEn) {
    return myNestedTree.visitChildren(new IVisitor<Node<MyObjectType>, MyObjectType>() {

        @Override
        public void component(Component object, IVisit<MyObjectType> visit) {
            if ( object instanceof Node) {
                if (((Node<PropertyEn>) object).getModelObject().getProto() == lxproto) {
                    visit.stop(((Node<PropertyEn>) object).getModelObject());
                }
                // A Node has no concept of nesting. The tree is made as such with other data structures.
                // No need to go deeper within an Node thus.
                visit.dontGoDeeper();
            }
        }
)};

Question

Why can't I just use a specialized Type as the first Type argument of IVisitor?


Solution

  • I found the problem... it's the signature of the visitChildren() method.

    The one I was using is :

    public final <R> R visitChildren(final IVisitor<Component, R> visitor) 
    { ... }
    

    The one I should be using is :

    public final <S extends Component, R> R visitChildren(final Class<?> clazz, final IVisitor<S, R> visitor)
    { ... }
    

    So the code would look like this:

    private MyObjectType findNode(final PropertyEn propertyEn) {
        return myNestedTree.visitChildren(Node.class, new IVisitor<Node<MyObjectType>, MyObjectType>() {
    
            @Override
            public void component(Node<MyObjectType> object, IVisit<MyObjectType> visit) {
            if ( object.getModelObject().getPropertyEn() == propertyEn ) {
                visit.stop(object.getModelObject());
            }
        }
    )};