Wicket
  1. Wicket
  2. WICKET-4259

Using an IValidator on an AjaxEditableLabel causes ClassCastException

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Minor Minor
    • Resolution: Fixed
    • Affects Version/s: 1.5.3
    • Fix Version/s: 1.5.4, 6.0.0-beta1
    • Component/s: wicket-extensions
    • Labels:
      None

      Description

      AjaxEditableLabel<Integer> label = new AjaxEditableLabel<Integer>("label", new PropertyModel<Integer>(this, "value"));
      form.add(label);
      label.setRequired(true);
      label.add(new RangeValidator<Integer>(1, 10));

      Using a RangeValidator<Integer> on an AjaxEditableLabel<Integer> causes an ClassCastException after editing the label.

      java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

      This can be avoided by setting the type explicit on the AjaxEditableLabel.

      label.setType(Integer.class);

      But this wasn't necessary in Wicket 1.4.19. In this version all works fine without setting the type explicit.

      I found out, that AbstractTextComponent.resolveType() is not able to get the type of the DefaultModel of the AjaxEditableLabel in Wicket 1.5.3.

      I will attach two QuickStarts to demonstrate the bug. One with wicket 1.4.19 and the other with Wicket 1.5.3

      1. myproject1_5_3.zip
        52 kB
        Stefan Schulte
      2. myproject1_4_19.zip
        18 kB
        Stefan Schulte
      3. WICKET-4259.patch
        2 kB
        Pedro Santos

        Activity

        Hide
        Stefan Schulte added a comment -

        Attached quickstart.

        Show
        Stefan Schulte added a comment - Attached quickstart.
        Hide
        Pedro Santos added a comment -

        possible fix

        Show
        Pedro Santos added a comment - possible fix
        Hide
        Martin Grigorov added a comment -

        It is interesting why it works in 1.4.x ?
        Is PropertyModel smarter in 1.4.x ? Did we lose some functionality ?

        Show
        Martin Grigorov added a comment - It is interesting why it works in 1.4.x ? Is PropertyModel smarter in 1.4.x ? Did we lose some functionality ?
        Hide
        Stefan Schulte added a comment - - edited

        Yes, I think we have lost some funcionality. The cause for that, I think, is not the PropertyModel. I found a difference in Component.getDefaultModel() which is called from AbstractTextComponent.resolveType().

        Place a breakpoint on Component.getDefaultModel() and then click on the AjaxEditableLabel. In the Wicket 1.4.19 project you will get a IModel of type PropertyModel<T>. The toString() value is:
        Model:classname=[org.apache.wicket.model.PropertyModel]:nestedModel=[[Page class = com.mycompany.FormPage, id = 0, version = 0, ajax = 1]]:expression=[value]

        In the Wicket 1.5.3 project you will get a model of type AjaxEditableLabel$3. The toString() value is:
        org.apache.wicket.extensions.ajax.markup.html.AjaxEditableLabel$3@a638fc

        Here is the call stack in Wicket 1.5.3 of getDefaultModel():

        Thread [qtp21307627-15] (Suspended (breakpoint at line 1616 in Component))
        AjaxEditableLabel$1(Component).getDefaultModel() line: 1616
        AjaxEditableLabel$1(AbstractTextComponent<T>).resolveType() line: 152
        AjaxEditableLabel$1(AbstractTextComponent<T>).onBeforeRender() line: 142
        AjaxEditableLabel$1(Component).internalBeforeRender() line: 981
        AjaxEditableLabel$1(Component).beforeRender() line: 1015
        AjaxEditableLabel<T>(MarkupContainer).onBeforeRenderChildren() line: 1785
        AjaxEditableLabel<T>(Component).onBeforeRender() line: 3774
        ...

        Show
        Stefan Schulte added a comment - - edited Yes, I think we have lost some funcionality. The cause for that, I think, is not the PropertyModel. I found a difference in Component.getDefaultModel() which is called from AbstractTextComponent.resolveType(). Place a breakpoint on Component.getDefaultModel() and then click on the AjaxEditableLabel. In the Wicket 1.4.19 project you will get a IModel of type PropertyModel<T>. The toString() value is: Model:classname= [org.apache.wicket.model.PropertyModel] :nestedModel=[ [Page class = com.mycompany.FormPage, id = 0, version = 0, ajax = 1] ]:expression= [value] In the Wicket 1.5.3 project you will get a model of type AjaxEditableLabel$3. The toString() value is: org.apache.wicket.extensions.ajax.markup.html.AjaxEditableLabel$3@a638fc Here is the call stack in Wicket 1.5.3 of getDefaultModel(): Thread [qtp21307627-15] (Suspended (breakpoint at line 1616 in Component)) AjaxEditableLabel$1(Component).getDefaultModel() line: 1616 AjaxEditableLabel$1(AbstractTextComponent<T>).resolveType() line: 152 AjaxEditableLabel$1(AbstractTextComponent<T>).onBeforeRender() line: 142 AjaxEditableLabel$1(Component).internalBeforeRender() line: 981 AjaxEditableLabel$1(Component).beforeRender() line: 1015 AjaxEditableLabel<T>(MarkupContainer).onBeforeRenderChildren() line: 1785 AjaxEditableLabel<T>(Component).onBeforeRender() line: 3774 ...
        Hide
        Martin Grigorov added a comment -

        Can you override org.apache.wicket.extensions.ajax.markup.html.AjaxEditableLabel.getDelegatingParentModel() to have toString() that just does: return getParentModel().toString(); and see what is the result ?

        Show
        Martin Grigorov added a comment - Can you override org.apache.wicket.extensions.ajax.markup.html.AjaxEditableLabel.getDelegatingParentModel() to have toString() that just does: return getParentModel().toString(); and see what is the result ?
        Hide
        Stefan Schulte added a comment -

        I made the following change:

        private IModel<T> getDelegatingParentModel() {
        return new IModel<T>() {
        private static final long serialVersionUID = 1L;

        public T getObject()

        { return getParentModel().getObject(); }

        public void setObject(final T object)

        { getParentModel().setObject(object); }

        public void detach()

        { getParentModel().detach(); }

        @Override
        public String toString()

        { return getParentModel().toString(); //my change }

        };
        }

        The output has changed now to the output in wicket 1.4.19:
        Model:classname=[org.apache.wicket.model.PropertyModel]:nestedModel=[[Page class = com.mycompany.FormPage, id = 1, render count = 1]]:expression=[value]

        Show
        Stefan Schulte added a comment - I made the following change: private IModel<T> getDelegatingParentModel() { return new IModel<T>() { private static final long serialVersionUID = 1L; public T getObject() { return getParentModel().getObject(); } public void setObject(final T object) { getParentModel().setObject(object); } public void detach() { getParentModel().detach(); } @Override public String toString() { return getParentModel().toString(); //my change } }; } The output has changed now to the output in wicket 1.4.19: Model:classname= [org.apache.wicket.model.PropertyModel] :nestedModel=[ [Page class = com.mycompany.FormPage, id = 1, render count = 1] ]:expression= [value]
        Hide
        Martin Grigorov added a comment -

        So, the problem is somewhere else ... I still bet on PropertyModel.

        Show
        Martin Grigorov added a comment - So, the problem is somewhere else ... I still bet on PropertyModel.
        Hide
        Stefan Schulte added a comment -

        Mmmh... after the call of getDefaultModel() AbstractTextComponent.getModelType(IModel<?> model) is called by resolveType(). In my examples this returns Integer.class in Wicket 1.4.19 and null in Wicket 1.5.3. And this because auf auf if(model instanceof IObjectClassAwareModel) returns false in Wicket 1.5.3. But I don't know why.

        Show
        Stefan Schulte added a comment - Mmmh... after the call of getDefaultModel() AbstractTextComponent.getModelType(IModel<?> model) is called by resolveType(). In my examples this returns Integer.class in Wicket 1.4.19 and null in Wicket 1.5.3. And this because auf auf if(model instanceof IObjectClassAwareModel) returns false in Wicket 1.5.3. But I don't know why.
        Hide
        Stefan Schulte added a comment -

        ... this is because AjaxEditableLabel.getDelegatingParentModel() returns an IModel and not an IObjectClassAwareModel. Wrapping the PropertyModel into an IModel causes the error I think!

        Show
        Stefan Schulte added a comment - ... this is because AjaxEditableLabel.getDelegatingParentModel() returns an IModel and not an IObjectClassAwareModel. Wrapping the PropertyModel into an IModel causes the error I think!
        Hide
        Martin Grigorov added a comment -

        I see.
        @Pedro: apply the patch.

        Show
        Martin Grigorov added a comment - I see. @Pedro: apply the patch.

          People

          • Assignee:
            Pedro Santos
            Reporter:
            Stefan Schulte
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development