Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    ClassCastException with getCanvasItem()

    This issue is occurring in SmartClient Version: v8.3p_2012-12-15/PowerEdition Deployment (built 2012-12-15)

    We have created a custom Combo input item, and have added a ChangedHandler for it. A problem is occurring when the user selects a value, specifically a ClassCastException occurs.

    Here is the code snippet:

    // A changed handler stores the value in the form's value manager.
    // Not that we can't refer to the item directly, we have to create
    // a new item from the event item's javascript. See DataSourceField.setEditorType()
    // for more information about the rules that need to be followed.
    cbItem.addChangedHandler(new ChangedHandler() {
    @Override
    public void onChanged(ChangedEvent event) {
    ComboBoxItem myCB = new ComboBoxItem(event.getItem().getJsObj());
    CanvasItem myCanvasItem = myCB.getForm().getCanvasItem();
    if (myCB.getValue()!=null)
    myCanvasItem.storeValue(myCB.getValueAsString());
    }
    });

    .
    .
    .

    // Create a form with the pickTree in it and set that as our canvas.
    DynamicForm form = new DynamicForm();
    form.setItemLayout(FormLayoutType.ABSOLUTE);
    form.setNumCols(1);
    form.setFields(cbItem);
    item.setCanvas(form);

    As it stands right now, when the user change the value of the cbItem, a low-level class cast exception happens on this line:

    CanvasItem myCanvasItem = myCB.getForm().getCanvasItem();

    This is because the getForm.getCanvasItem() returns a FormItem and not a CanvasItem. The FormItem cannot be cast as a CanvasItem when the getCanvasItem method is invoked...

    As a workaround, I tried encapsulating the Form in a more traditional canvas like this:

    HLayout formLay = new HLayout();
    formLay.setMembers(form);
    formLay.setAutoHeight();
    formLay.setAutoWidth();
    formLay.setOverflow(Overflow.VISIBLE);

    item.setCanvas(formLay);

    This fixes the class cast exception, but then again, then code still does not work... NPE in this case further in the code a few lines later.

    Here is the stack trace for this issue as well:

    com.google.gwt.event.shared.UmbrellaException: One or more exceptions caught, see full set in UmbrellaException#getCauses
    at com.google.gwt.event.shared.HandlerManager.fireEvent(HandlerManager.java:129)
    at com.smartgwt.client.core.DataClass.fireEvent(DataClass.java:228)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
    at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
    at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
    at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:337)
    at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:218)
    at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136)
    at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:561)
    at com.google.gwt.dev.shell.ModuleSpace.invokeNativeObject(ModuleSpace.java:269)
    at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeObject(JavaScriptHost.java:91)
    at com.google.gwt.core.client.impl.Impl.apply(Impl.java)
    at com.google.gwt.core.client.impl.Impl.entry0(Impl.java:213)
    at sun.reflect.GeneratedMethodAccessor47.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
    at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
    at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
    at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:292)
    at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:546)
    at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:363)
    at java.lang.Thread.run(Thread.java:680)
    Caused by: java.lang.ClassCastException: com.smartgwt.client.widgets.form.fields.FormItem cannot be cast to com.smartgwt.client.widgets.form.fields.CanvasItem
    at com.smartgwt.client.widgets.form.fields.CanvasItem.getOrCreateRef(CanvasItem.java:117)
    at com.smartgwt.client.widgets.Canvas.getCanvasItem(Canvas.java:1046)
    at com.islandpacific.gui.client.IpCodeNameCombobox$1$2.onChanged(IpCodeNameCombobox.java:115)
    at com.smartgwt.client.widgets.form.fields.events.ChangedEvent.dispatch(ChangedEvent.java:100)
    at com.smartgwt.client.widgets.form.fields.events.ChangedEvent.dispatch(ChangedEvent.java:1)
    at com.google.gwt.event.shared.GwtEvent.dispatch(GwtEvent.java:1)
    at com.google.web.bindery.event.shared.EventBus.dispatchEvent(EventBus.java:40)
    at com.google.web.bindery.event.shared.SimpleEventBus.doFire(SimpleEventBus.java:193)
    at com.google.web.bindery.event.shared.SimpleEventBus.fireEvent(SimpleEventBus.java:88)
    at com.google.gwt.event.shared.HandlerManager.fireEvent(HandlerManager.java:127)
    at com.smartgwt.client.core.DataClass.fireEvent(DataClass.java:228)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
    at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
    at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
    at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:337)
    at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:218)
    at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136)
    at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:561)
    at com.google.gwt.dev.shell.ModuleSpace.invokeNativeObject(ModuleSpace.java:269)
    at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeObject(JavaScriptHost.java:91)
    at com.google.gwt.core.client.impl.Impl.apply(Impl.java)
    at com.google.gwt.core.client.impl.Impl.entry0(Impl.java:213)
    at sun.reflect.GeneratedMethodAccessor47.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
    at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
    at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
    at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:292)
    at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:546)
    at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:363)
    at java.lang.Thread.run(Thread.java:680)

    #2
    Correction on the build

    This problem is occurring on the 2/27 build.

    Comment


      #3
      We can't reproduce this. Below is some sample code that shows the API working as expected.

      Can you show how you're ending up with a FormItem being returned?

      Code:
          	ComboBoxItem cbItem = new ComboBoxItem();
              cbItem.addChangedHandler(new ChangedHandler() {
                  @Override
                  public void onChanged(ChangedEvent event) {
                          ComboBoxItem myCB = new ComboBoxItem(event.getItem().getJsObj());
                          CanvasItem myCanvasItem = myCB.getForm().getCanvasItem();
      
                          if (myCB.getValue()!=null)
                                  myCanvasItem.storeValue(myCB.getValueAsString());
                  }
              });
      
              DynamicForm form = new DynamicForm();
              form.setItemLayout(FormLayoutType.ABSOLUTE);
              form.setNumCols(1);
              form.setFields(cbItem);
              
              CanvasItem canvasItem = new CanvasItem();
              canvasItem.setCanvas(form);
              
              DynamicForm form2 = new DynamicForm();
              form2.setFields(canvasItem);
              form2.draw();

      Comment


        #4
        I work with ecruz, and he asked me to take a look at what was going on. I've fixed it for him, but I'm not entirely sure whether it should have worked the way it was or not. I think I know what you're going to say, and if I'm right, I'll probably post a follow-up thread for clarification.

        Anyway.

        There's a dataSoureField declared with an editorType attribute like so:

        Code:
        <field name="itemVendor" ... editorType="MyCustomCanvasItem"/>
        and then there's this thing in the EntryPoint that iterates over every field in every datasource, after they've been loaded, checks for that editorType attribute, and calls DataSourceField.setEditorType.

        Code:
        if ("MyCustomCanvasItem".equals(editorType)) {
          field.setEditorType(new MyCustomCanvasItem());
        }
        Finally, there was a DynamicForm that wanted to bind to one of these altered DataSourceFields

        Code:
        DynamicForm form = new DynamicForm();
        form.setDataSource("Item");
        form.setFields(new FormItem("itemVendor"));
        where the expectation was that the new FormItem was going to get the DataSourceField's metadata, including the editorType. Well, it does get the editorType, clearly. It's just that the type cast was returning a FormItem and not its editorType.

        Can you confirm what the behavior should have been? And perhaps whether it's better to

        Code:
        FormItem item = new FormItem("itemVendor");
        item.setEditorType(new MyCustomCanvasItem());
        form.setFields(item);
        or

        Code:
        MyCustomCanvasItem item = new MyCustomCanvasItem("itemVendor"));
        form.setFields(item);
        Last edited by bbruyn; 15 Mar 2013, 10:46.

        Comment


          #5
          Right, your latter code snippets are the right approach. When you provide a FormItem like that, we take you seriously that that's the type you want to use. Consider if you had provided an instance of "MyEvenMoreCustomCanvasItem" - you would expect that to override editorType from the DataSource.

          Just as an aside, we will soon have support for specifying editorType as the FQN of a custom Java subclass of FormItem in the DataSource file. This has been a while coming since we basically had to build the equivalent of Java reflection into GWT.

          Comment


            #6
            Originally posted by Isomorphic View Post
            Just as an aside, we will soon have support for specifying editorType as the FQN of a custom Java subclass of FormItem in the DataSource file. This has been a while coming since we basically had to build the equivalent of Java reflection into GWT.
            Hello, Isomorphic!

            Is there any advance for this reflection feature since then?

            Comment


              #7
              Yes, just take a look at the updated docs for DataSourceField.editorType.

              Comment

              Working...
              X