11 Replies Latest reply on Dec 16, 2013 4:23 PM by Christian Sadilek

    declarative data binding with GWT uIBinder injected widgets

    Anthony Foulfoin Newbie

      Hi,

       

      I'm currently trying to use Errai data binding as a standalone in an existing GWT app.

       

      In this app all the widgets are inject using the GWT UiBinder and @UiField annotation. I would like to use the annotation based data binding in order to have something like that :

       

      @UiField
      @Bound
      TextBox name;
      

       

      But it just doesn't work. Maybe it works only with Errai Ui widgets.

      Is there any way to make Errai data binding annotions and GWT UiBinder working together ?

       

      Thanks

        • 1. Re: declarative data binding with GWT uIBinder injected widgets
          Christian Sadilek Master

          Hi Anthony,

           

          Yes, you can use declarative data binding without Errai UI. You have to make sure though that the bean that declares the @Bound fields is managed by Errai IOC. If you want to combine it with GWTs UiBinder you will need to inherit Errai's UiBinder module (and add the errai-uibinder jar to your classpath):

           

          <inherits name="org.jboss.errai.uibinder.UIBinderForIOC" />
          

           

          To make sure your bean is managed by Errai IOC, simply annotate it with a scope (e.g. @Dependent). You can then also simply inject UiBinder instances. That means you can replace code like this

           

          public class EditContactView extends Composite {  
          
            interface EditContactViewUiBinder extends UiBinder<Panel, EditContactView> {}
            private static EditContactViewUiBinder uiBinder =  
                GWT.create(EditContactViewUiBinder.class);
          
            ...
          }
          
          }
          

           

          with this

           

          @Dependent
          public class EditContactView extends Composite {
          
            @Inject 
            UiBinder<Panel, EditContactView> uiBinder;
          
            ...
          }
          
            ...
          }
          

           

          EditContactView would contain all your @Bound @UiField. You can then @Inject this view anywhere you like (e.g. in your Presenter class if you use the MVP pattern).

           

          Cheers,

          Christian

          1 of 1 people found this helpful
          • 2. Re: Re: declarative data binding with GWT uIBinder injected widgets
            Anthony Foulfoin Newbie

            Hi Christian,

             

            Thank you for your answer, I've added the module you specified, and now I'm having the following Errai modules :

             

                <inherits name="org.jboss.errai.common.ErraiCommon" />
                <inherits name="org.jboss.errai.ioc.Container" />
                <inherits name="org.jboss.errai.databinding.DataBinding" />
                <inherits name="org.jboss.errai.enterprise.CDI"/>
                <inherits name="org.jboss.errai.uibinder.UIBinderForIOC" />
            

             

            But when I compile the app, I get the following error :

             

            Computing all possible rebind results for 'org.jboss.errai.ioc.client.BootstrapperImpl.fr_carboatmedia_oasis_ui_client_professional_contact_clientEdi_composite_ProfessionalEdiAddContactPopup_UiBinder'

             

            [INFO]       Rebinding org.jboss.errai.ioc.client.BootstrapperImpl.fr_carboatmedia_oasis_ui_client_professional_contact_clientEdi_composite_ProfessionalEdiAddContactPopup_UiBinder
            [INFO]          Invoking generator com.google.gwt.uibinder.rebind.UiBinderGenerator
            [INFO]             [ERROR] Unable to find resource: org/jboss/errai/ioc/client/ProfessionalEdiAddContactPopupStyle.css
            [INFO]             [ERROR] Can't interpret CSS
            [INFO]             [ERROR] Could not find no-arg method named descriptionLabelCourt in type com.google.gwt.resources.client.CssResource
            [INFO]    [ERROR] Errors in 'gen/org/jboss/errai/ioc/client/BootstrapperImpl.java'
            [INFO]       [ERROR] Line 49: Failed to resolve 'org.jboss.errai.ioc.client.BootstrapperImpl.fr_carboatmedia_oasis_ui_client_professional_contact_clientEdi_composite_ProfessionalEdiAddContactPopup_UiBinder' via deferred binding
            [INFO]    [WARN] For the following type(s), generated source was never committed (did you forget to call commit()?)
            [INFO]       [WARN] org.jboss.errai.ioc.client.BootstrapperImpl_fr_carboatmedia_oasis_ui_client_professional_contact_clientEdi_composite_ProfessionalEdiAddContactPopup_UiBinderImpl
            [INFO]    Computing all possible rebind results for 'org.jboss.errai.ioc.client.QualifierEqualityFactory'
            [INFO]       Rebinding org.jboss.errai.ioc.client.QualifierEqualityFactory
            [INFO]          Invoking generator org.jboss.errai.ioc.rebind.ioc.bootstrapper.QualifierEqualityFactoryGenerator
            [INFO]             Generating Extensions Bootstrapper...
            [INFO]       Rebinding org.jboss.errai.ioc.client.QualifierEqualityFactory
            [INFO]          Invoking generator org.jboss.errai.ioc.rebind.ioc.bootstrapper.QualifierEqualityFactoryGenerator
            

             

            So I tried to replace all the modules by only this one :

             

            <inherits name="org.jboss.errai.enterprise.All" />
            

             

            But I'm also getting an error :

             

            [INFO]             generating ioc bootstrapping code...
            [ERROR] java.util.concurrent.ExecutionException: org.jboss.errai.ioc.rebind.ioc.exception.UnsatisfiedDependenciesException:  @> fr.carboatmedia.oasis.ui.client.professional.contact.clientEdi.composite.ProfessionalEdiAddContactPopup
            [ERROR]  - field org.jboss.errai.codegen.meta.MetaField:fr.carboatmedia.oasis.ui.client.professional.contact.clientEdi.composite.ProfessionalEdiAddContactPopup.uiBinder could not be satisfied for type: com.google.gwt.uibinder.client.UiBinder
            [ERROR]   Message: can't resolve bean: com.google.gwt.uibinder.client.UiBinder<com.google.gwt.user.client.ui.Widget, fr.carboatmedia.oasis.ui.client.professional.contact.clientEdi.composite.ProfessionalEdiAddContactPopup> ( @Default  @Any )
            

             

            I'm injecting the uibinder in my view, and view is created throw IOC :

             

            @Dependent
            public class ProfessionalEdiAddContactPopup extends Composite {
            
              @Inject
              private UiBinder<Panel, ProfessionalEdiAddContactPopup> uiBinder;
            

             

            Thanks for your help !

            • 3. Re: declarative data binding with GWT uIBinder injected widgets
              Anthony Foulfoin Newbie

              One more thing,

               

              If i create the UiBinder with the GWT way :

               

              interface ProfessionalEdiAddContactPopupUiBinder extends UiBinder<Widget, ProfessionalEdiAddContactPopup> {}
              private ProfessionalEdiAddContactPopupUiBinder uiBinder = GWT.create(ProfessionalEdiAddContactPopupUiBinder.class);

               

              The app compiles and the binding works like a charm

               

              So the only remaining problem is that I'm not able to directly @Inject the UiBinder

              • 4. Re: declarative data binding with GWT uIBinder injected widgets
                Christian Sadilek Master

                Hi Anthony,

                 

                That's good news! For the UiBinder to be injectable you will still need to inherit the errai-uibinder module. It is not included in errai-javaee-all.

                 

                Cheers,

                Christian

                • 5. Re: Re: declarative data binding with GWT uIBinder injected widgets
                  Anthony Foulfoin Newbie

                  Hi,

                   

                  The problem is still here bu I have some fresh news.

                  In my uiBinder xml file, I define the css resource like that :

                   

                  <ui:style src="ProfessionalEdiAddContactPopupStyle.css" />
                  

                   

                  Injecting the UiBinder with errai produces the following error at compile time :

                   

                  Computing all possible rebind results for 'org.jboss.errai.ioc.client.BootstrapperImpl.fr_carboatmedia_oasis_ui_client_professional_contact_clientEdi_composite_ProfessionalEdiAddContactPopup_UiBinder'
                  [INFO]       Rebinding org.jboss.errai.ioc.client.BootstrapperImpl.fr_carboatmedia_oasis_ui_client_professional_contact_clientEdi_composite_ProfessionalEdiAddContactPopup_UiBinder
                  [INFO]          Invoking generator com.google.gwt.uibinder.rebind.UiBinderGenerator
                  [INFO]             [ERROR] Unable to find resource: org/jboss/errai/ioc/client/ProfessionalEdiAddContactPopupStyle.css
                  [INFO]    [ERROR] Errors in 'gen/org/jboss/errai/ioc/client/BootstrapperImpl.java'
                  [INFO]       [ERROR] Line 52: Failed to resolve 'org.jboss.errai.ioc.client.BootstrapperImpl.fr_carboatmedia_oasis_ui_client_professional_contact_clientEdi_composite_ProfessionalEdiAddContactPopup_UiBinder' via deferred binding
                  [INFO]    [WARN] For the following type(s), generated source was never committed (did you forget to call commit()?)
                  [INFO]       [WARN] org.jboss.errai.ioc.client.BootstrapperImpl_fr_carboatmedia_oasis_ui_client_professional_contact_clientEdi_composite_ProfessionalEdiAddContactPopup_UiBinderImpl_GenCss_style
                  [INFO]       [WARN] org.jboss.errai.ioc.client.BootstrapperImpl_fr_carboatmedia_oasis_ui_client_professional_contact_clientEdi_composite_ProfessionalEdiAddContactPopup_UiBinderImpl_GenBundle
                  [INFO]       [WARN] org.jboss.errai.ioc.client.BootstrapperImpl_fr_carboatmedia_oasis_ui_client_professional_contact_clientEdi_composite_ProfessionalEdiAddContactPopup_UiBinderImpl
                  

                   

                  The interesting line is this one :

                   

                  [ERROR] Unable to find resource: org/jboss/errai/ioc/client/ProfessionalEdiAddContactPopupStyle.css
                  

                   

                  Errai is looking for my CSS file in the wrong folder.

                  BUT, if if define my CSS file with an absolute path (e.g. com/mycompany/ProfessionalEdiAddContactPopupStyle.css) rather than a relative one, it works. This bug does not occures when the UiBinder is created with the GWT.create(), so it could be a bug coming from errai.

                   

                  Once this problem is solved, another one appears. Here is one attribute of my view :

                   

                  @UiField
                  @Bound(property = "email")
                  TextBox mailTextBox;
                  

                   

                  Errai produces the following errors at compile time :

                   

                  [INFO]    [ERROR] Errors in 'C:\dev\workspaces\oasis\oasis_trunk\oasis-ui\target\.generated\org\jboss\errai\ioc\client\BootstrapperImpl_fr_carboatmedia_oasis_ui_client_professional_contact_clientEdi_composite_ProfessionalEdiAddContactPopup_UiBinderImpl.java'
                  [INFO]       [ERROR] Line 171: The field ProfessionalEdiAddContactPopup.mailTextBox is not visible
                  

                   

                  I had to declare my attribute as 'public' in order to make this error disappeared, but using @UiField on attributes with a visibility different than 'public' works well with the classic GWT UiBinder.

                   

                  Once I declared all my injected widget as public, I encountered a new Error message ;

                   

                  [INFO] 16:28:57.104 [pool-4-thread-5] WARN  o.jboss.errai.config.rebind.EnvUtil - reachability analysis disabled. errai may generate unnecessary code.
                  [INFO] 16:28:57.104 [pool-4-thread-5] WARN  o.jboss.errai.config.rebind.EnvUtil - enable reachability analysis with -Derrai.compile.perf.perform_reachability_analysis=true
                  [INFO] 16:28:57.104 [pool-4-thread-5] INFO  o.j.e.m.r.MarshallerGeneratorFactory - generating marshalling class...
                  [INFO] 16:28:57.174 [pool-4-thread-5] INFO  o.j.e.m.r.MarshallerGeneratorFactory - generated marshalling class in 70ms.
                  [ERROR] org.jboss.errai.codegen.exception.UndefinedMethodException: undefined method: _$807284019__$1937953969_partnerListBox(fr.carboatmedia.oasis.ui.client.professional.contact.clientEdi.composite.ProfessionalEdiAddContactPopup, fr.carboatmedia.oasis.ui.client.common.custom.SelectListBox); in class: org.jboss.errai.ioc.client.BootstrapperImpl
                  [ERROR]         at org.jboss.errai.codegen.builder.callstack.MethodCall.handleCall(MethodCall.java:73)
                  [ERROR]         at org.jboss.errai.codegen.builder.callstack.AbstractCallElement.nextOrReturn(AbstractCallElement.java:46)
                  [ERROR]         at org.jboss.errai.codegen.builder.callstack.LoadClassReference.handleCall(LoadClassReference.java:48)
                  [ERROR]         at org.jboss.errai.codegen.builder.impl.AbstractStatementBuilder.generate(AbstractStatementBuilder.java:61)
                  [ERROR]         at org.jboss.errai.codegen.BlockStatement.generate(BlockStatement.java:90)
                  [ERROR]         at org.jboss.errai.codegen.control.IfBlock.generate(IfBlock.java:65)
                  [ERROR]         at org.jboss.errai.codegen.builder.callstack.ConditionalBlockCallElement.handleCall(ConditionalBlockCallElement.java:46)
                  [ERROR]         at org.jboss.errai.codegen.builder.impl.AbstractStatementBuilder.generate(AbstractStatementBuilder.java:61)
                  
                  

                   

                  For this error, I didn't find any dirty solution yet :s

                  I hope all this details will help you to fix or improve this great api .

                   

                  Cheers,

                  Anthony.

                  • 6. Re: declarative data binding with GWT uIBinder injected widgets
                    Christian Sadilek Master

                    Hi Anthony,

                     

                    Thanks for digging into this. We haven't really continued development on Errai's UiBinder module ever since we added Errai UI. Since you already have Errai's declarative data binding working with GWTs native UiBinder I'd recommend leaving out Errai's UiBinder module for now. Of course you're welcome to send a pull request with a fix to this module if you're interested and/or create a JIRA for us!

                     

                    Cheers,

                    Christian

                    • 7. Re: declarative data binding with GWT uIBinder injected widgets
                      Anthony Foulfoin Newbie

                      Thanks for your answer.

                       

                      I will continue to use GWT native UiBinder for now, And I'll make a pull request or a jira if I don't have enough time for the pull .

                       

                      Cheers,

                      Anthony

                      • 8. Re: Re: declarative data binding with GWT uIBinder injected widgets
                        Nick Alexander Newbie

                        Hi, Just some more on this,

                         

                        I have been having a similar issue.

                        Regardless if I use the Injected uiBinder or the GWT.create one I cannot get declarative binding to work.

                         

                        I have managed to get binding to to work using the @PostConstruct annotated method with something like this

                         

                        @PostConstruct

                            public void init() {

                         

                          initWidget(uiBinder.createAndBindUi(this));

                         

                              ContactImpl contact = contactBinder

                                      .bind(firstName, "firstName")

                                      .bind(lastName, "lastName")

                                      .getModel();

                              contact.setFirstName("Mad");

                              contact.setLastName("Max");

                           

                          }

                         

                        but allow get a org.jboss.errai.codegen.exception.UndefinedMethodException

                        when using the declarative binding. This is really pain.


                        Will have a look at the code to see whats there. Another issue is that Binding requires HasValue or HasText interface on the widget according to the  BindableProxyAgent javadoc  although this is not mentioned anywhere in the Wiki. Would it not make sense to support standard GWT Editors and Adaptors for Data-binding?

                         

                        Nick

                        • 9. Re: declarative data binding with GWT uIBinder injected widgets
                          Christian Sadilek Master

                          Hi Nick,

                           

                          Although we've been focusing on Errai UI because we think it's a better alternative to UiBinder you should still be able to at least make declarative binding work with GWT's UiBinder (as Anthony and others did).

                           

                          Can you provide all exception details of the UndefinedMethodException you're getting (error message and stacktrace)? Using GWT.create instead of the injected UiBinder and removing Errai's UiBinder module from your gwt.xml and classpath should make the problem go away.

                           

                          Regarding GWT Editors, I am not sure that would make sense, to be honest. The GWT Editor framework is really an alternative approach to data binding. I am not sure about the benefits of mixing these two other than migrating existing code.

                           

                          Cheers,

                          Christian

                          • 10. Re: Re: declarative data binding with GWT uIBinder injected widgets
                            Nick Alexander Newbie

                            Hi Christian, did a GIT Pull and have isolated the bug.

                             

                            org.jboss.errai.databinding.rebind.BoundDecorator in the generateDecorator method

                             

                            if (widgetType.isAssignableTo(Widget.class)) {

                                    // Ensure @Bound widget field is initialized

                                    if (!ctx.isAnnotationPresent(UiField.class) && !ctx.isAnnotationPresent(Inject.class) && ctx.getField() != null && widgetType.isDefaultInstantiable()) {

                                      Statement widgetInit = Stmt.invokeStatic(

                                          ctx.getInjectionContext().getProcessingContext().getBootstrapClass(),

                                          PrivateAccessUtil.getPrivateFieldInjectorName(ctx.getField()),

                                          Refs.get(ctx.getInjector().getInstanceVarName()),

                                          ObjectBuilder.newInstanceOf(widgetType));

                             

                                      statements.add(If.isNull(widget).append(widgetInit).finish());

                                    }

                                  }

                             

                            I added the condition check for the UIField as the ctx.getInjectionContext().getProcessingContext().getBootstrapClass() call references a non existing field in the BootStrapper class.

                            This is obviously not a complete solution to the problem as it does not address UIFactory methods or UIField(provided=true), I will look at addressing this issues if i have time and write some tests around this.

                             

                            Nick Alexander