2 Replies Latest reply on Sep 5, 2016 7:22 AM by aofner

    Errai and Polymer

    Aaron Anderson Newbie

      In case anyone is interested I was able to utilize the Vaadin Polymer GWT 2.8 JSInterop classes with Errai templates. Additionally I was able to use the Vaadin Polymer gwt-api-generator to generate JSInterop classes for Polymer app-layout elements. At some point when I have time I would like to provide a public example of the-end-to end process but until then here is an overall description of the process:

       

      1) install NPM, Bower, and the Vaadin API generator

      sudo apt-get install npm

      sudo npm install -g bower

      sudo npm install -g vaadin/gwt-api-generator

       

      2) In an empy directory generate the JSInterop stubs. Skip this step if you are using only standard Polymer libraries

      gwt-api-generator --package "PolymerLabs/app-layout `realpath ../web/bower.json`"  --groupId=com.mycompany.polymer --artifactId=polymer-gwt --version 0.0.1 --pom

       

      Note that the contents of of ../web is just a directory where I place my own Polymer elements that I want to generate bindings for. The bower.json looks like

      {

        "name": "mycompany-web",

        "version": "0.0.1",

        "description": "My Company Common Web Components",

        "private": true

      }

       

      run mvn clean install to compile the JSInerop classes

       

      3) In the main maven project  add the Errai dependencies plus the Vaadin ones

       

      <dependency>

                              <groupId>com.vaadin.polymer</groupId>

                              <artifactId>vaadin-gwt-polymer-elements</artifactId>

                              <scope>provided</scope>

                      </dependency>

       

                      <dependency>

                              <groupId>com.mycompany.polymer</groupId>

                              <artifactId>polymer-gwt</artifactId>

                              <version>${project.version}</version>

                              <scope>provided</scope>

                      </dependency>

       

      Since GWT/Errai asset generation is performed at compile time one can set all the GWT/Errai dependencies to the maven provided scope so they are not added to the WAR archive. Obviously if one is using server side features such as WebSockets, CDI, etc those libraries will need to be in the compile scope.

       

      4) Add an empty Errai.properies file in src/main/resources to enable Errai extensions and then add this class to the project:

       

      package mycompany.rebind;

       

       

      import static org.jboss.errai.codegen.util.Stmt.declareFinalVariable;

      import static org.jboss.errai.codegen.util.Stmt.invokeStatic;

      import static org.jboss.errai.codegen.util.Stmt.loadLiteral;

      import static org.jboss.errai.codegen.util.Stmt.loadVariable;

       

       

      import java.lang.reflect.Field;

      import java.util.ArrayList;

      import java.util.Collections;

      import java.util.List;

      import java.util.logging.Logger;

       

       

      import javax.enterprise.context.Dependent;

       

       

      import org.jboss.errai.codegen.Statement;

      import org.jboss.errai.codegen.builder.ClassStructureBuilder;

      import org.jboss.errai.codegen.meta.MetaClass;

      import org.jboss.errai.codegen.meta.MetaClassFactory;

      import org.jboss.errai.common.server.api.ErraiBootstrapFailure;

      import org.jboss.errai.ioc.client.api.IOCExtension;

      import org.jboss.errai.ioc.rebind.ioc.bootstrapper.AbstractBodyGenerator;

      import org.jboss.errai.ioc.rebind.ioc.bootstrapper.FactoryBodyGenerator;

      import org.jboss.errai.ioc.rebind.ioc.bootstrapper.IOCProcessingContext;

      import org.jboss.errai.ioc.rebind.ioc.extension.IOCExtensionConfigurator;

      import org.jboss.errai.ioc.rebind.ioc.graph.api.CustomFactoryInjectable;

      import org.jboss.errai.ioc.rebind.ioc.graph.api.DependencyGraph;

      import org.jboss.errai.ioc.rebind.ioc.graph.api.DependencyGraphBuilder.InjectableType;

      import org.jboss.errai.ioc.rebind.ioc.graph.api.Injectable;

      import org.jboss.errai.ioc.rebind.ioc.graph.api.InjectionSite;

      import org.jboss.errai.ioc.rebind.ioc.graph.impl.DefaultCustomFactoryInjectable;

      import org.jboss.errai.ioc.rebind.ioc.graph.impl.FactoryNameGenerator;

      import org.jboss.errai.ioc.rebind.ioc.graph.impl.InjectableHandle;

      import org.jboss.errai.ioc.rebind.ioc.injector.api.ExtensionTypeCallback;

      import org.jboss.errai.ioc.rebind.ioc.injector.api.InjectableProvider;

      import org.jboss.errai.ioc.rebind.ioc.injector.api.InjectionContext;

      import org.jboss.errai.ioc.rebind.ioc.injector.api.WiringElementType;

      import org.jboss.errai.ui.shared.TemplateUtil;

       

       

      import com.google.gwt.dom.client.Document;

      import com.vaadin.polymer.elemental.HTMLElement;

       

       

      import jsinterop.annotations.JsType;

       

       

      @IOCExtension

      public class VaadinPolymerIOCExtension implements IOCExtensionConfigurator {

        Logger logger = Logger.getLogger(VaadinPolymerIOCExtension.class.getName());

       

       

        @Override

        public void configure(IOCProcessingContext context, InjectionContext injectionContext) {

       

       

        }

       

       

        @Override

        public void afterInitialization(IOCProcessingContext context, InjectionContext injectionContext) {

        final MetaClass polymerClazz = MetaClassFactory.get(HTMLElement.class);

        injectionContext.registerExtensionTypeCallback(new ExtensionTypeCallback() {

       

       

        @Override

        public void callback(final MetaClass type) {

        if (type.isAssignableTo(polymerClazz)) {

        // org.jboss.errai.codegen.meta.impl.gwt.GWTClass MetaClass

        // implementation filters by class vs interface so convert

        // to Java reflection type to iterate over fields

        try {

        for (Field field : type.asClass().getDeclaredFields()) {

       

       

        if ("TAG".equals(field.getName())) {

        String tagName = (String) field.get(null);

        final JsType jsTypeAnno;

        if ((jsTypeAnno = type.getAnnotation(JsType.class)) == null || !jsTypeAnno.isNative()) {

        throw new RuntimeException(HTMLElement.class.getSimpleName() + " is only valid on native " + JsType.class.getSimpleName() + "s.");

        }

        addProviderForVaadinPolymerType(injectionContext, type, tagName);

        }

        }

        } catch (IllegalAccessException ie) {

        throw new ErraiBootstrapFailure(ie);

        }

        }

        }

        });

       

       

        }

       

       

        private void addProviderForVaadinPolymerType(final InjectionContext injectionContext, final MetaClass polymerType, String tagName) {

        if (polymerType.isPublic()) {

        final InjectableHandle handle = new InjectableHandle(polymerType, injectionContext.getQualifierFactory().forDefault());

        injectionContext.registerExactTypeInjectableProvider(handle, new InjectableProvider() {

       

       

        private CustomFactoryInjectable provided;

       

       

        @Override

        public CustomFactoryInjectable getInjectable(final InjectionSite injectionSite, final FactoryNameGenerator nameGenerator) {

        if (provided == null) {

        final FactoryBodyGenerator generator = new AbstractBodyGenerator() {

       

       

        @Override

        protected List<Statement> generateCreateInstanceStatements(final ClassStructureBuilder<?> bodyBlockBuilder, final Injectable injectable, final DependencyGraph graph, final InjectionContext injectionContext) {

        final List<Statement> stmts = new ArrayList<Statement>();

        final String elementVar = "element";

       

       

        stmts.add(declareFinalVariable(elementVar, com.google.gwt.dom.client.Element.class, invokeStatic(Document.class, "get").invoke("createElement", loadLiteral(tagName))));

       

       

        final String retValVar = "retVal";

        stmts.add(declareFinalVariable(retValVar, polymerType, invokeStatic(TemplateUtil.class, "nativeCast", loadVariable(elementVar))));

       

       

        stmts.add(loadVariable(retValVar).returnValue());

       

       

        return stmts;

        }

       

       

        };

        provided = new DefaultCustomFactoryInjectable(handle.getType(), handle.getQualifier(), nameGenerator.generateFor(handle.getType(), handle.getQualifier(), InjectableType.ExtensionProvided), Dependent.class, Collections.singletonList(WiringElementType.DependentBean), generator);

        }

       

       

        return provided;

        }

        });

        }

        }

       

       

      }

       

      After this one may inject the Vaadin generated JSInterop classes into Errai templates just as any other template composite.