0

Could you please help me to solve my problem with GWT Generator? Let me explain.

I wish to generate a widget (ListBox with pre-defined values) during the compilation time and I use GWT Generator for that. My solution works as expected in DevMode (when I run the project with mvn gwt:run) and I see the generated listbox on the screen. But when I compile the code and run it in the "Production mode" (using command mvn clean gwt:compile jetty:run-war) I see the dumb listbox with only one item "no-value" instead.

I have one idea about the issue reason. I use GIN in my project. Despite the fact, that I substitute my empty listbox with generated one using Deferred Binding but not GIN Injection, it probably somehow prevents the substitution during the runtime. I tried my listbox on an empty testing project - everything worked as desired in both Dev Mode and Production Mode. But it fails on my working project.

Here is my realisation:

package com.test.generated;

import com.google.gwt.user.client.ui.IsWidget;
public interface IMySelectBox extends IsWidget {}

My empty selectbox:

package com.test.generated;
import com.google.gwt.user.client.ui.ListBox;

/**
 * <p>Dumb listbox. It should be replaced with generated file.</p>
 * 
 */
public class MySelectBox implements IMySelectBox {

    @Override
    public ListBox asWidget() {
        ListBox listBox = new ListBox();
        listBox.addItem("no-value","no-value");
        return listBox;
    }
}  

My Generator:

package com.test.generated;

import java.io.PrintWriter;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;

/**
 * Generates the ListBox and populates it
 *
 */
public class SelectBoxGenerator extends Generator {

    /**
     * {@inheritDoc}
     */
    @Override
    public String generate(TreeLogger logger, GeneratorContext context, String typeName) throws UnableToCompleteException {

        try {

            JClassType classType = context.getTypeOracle().getType(typeName);
            return this.getSourceWriter(classType, context, logger);

        } catch (NotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Generates the source code of the List box.
     */
    private String getSourceWriter(JClassType classType, GeneratorContext context, TreeLogger logger) {

        final String packageName = classType.getPackage().getName();
        final String className = classType.getSimpleSourceName() + "GeneratedImpl";

        PrintWriter printWriter = context.tryCreate(logger, packageName, className);
        if (printWriter == null) {
            // source code has already been generated, abort
            return null;
        }

        ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(packageName, className);

        // Extends 
        composer.setSuperclass(classType.getName());

        // Implements interface IMySelectBox
        composer.addImplementedInterface(IMySelectBox.class.getSimpleName());

        // Imports
        composer.addImport(ListBox.class.getName());

        // Class body
        SourceWriter src = composer.createSourceWriter(context, printWriter);

        src.println("@Override");
        src.println("public ListBox asWidget() {");     
        src.println("ListBox sb = new ListBox();");

        // ...here I generate values for the selectbox during compilation time.

        src.println("return sb;");
        src.println("}");

        src.commit(logger);

        System.out.println("Generating for: " + className);

        // return the fully qualifed name of the generated class
        return packageName + "." + className;
    }
}

This is how I declare the substitution in my module.gwt.xml file:

  <generate-with class="com.test.generated.SelectBoxGenerator">
    <when-type-assignable class="com.test.generated.IMySelectBox" />
  </generate-with>

And I use my generated ListBox as usually:

IMySelectBox mySelectBox = GWT.create(MySelectBox.class);
anyPanel.add(mySelectBox);

As you can see, I don't touch GIN stuff here at all. I use GIN to inject my modules and views. I found Issue 95 in GIN website, probably it is related to my case.

I will be really glad to get any help. Any explanations, hints, workarounds, suggestions are welcome!

Thank you very much in advance!

  • First thing to do to debug generators: look at the generated code. The gwt-maven-plugin outputs generated code by default in `target/.generated`. You should find there why GIN would use your empty `MySelectBox` rather than the generated one. – Thomas Broyer Jul 25 '13 at 08:48
  • Thank you for the reply. Yes, I see the generated Java code in the `target/.generated` folder. I even see my generated selectox in generated Javascript code (I searched it using `grep` command)! It seems, that GWT (or GIN) generates correctly all the implementations, but just can't inject/bind it in runtime. – Ilja Hämäläinen Jul 25 '13 at 09:14
  • But there's no "at runtime", everything's decided at compile-time with GWT. Dig into the generated code (including code generated by GIN) to understand why it doesn't use the correct class (add `target/.generated` as a source folder in your IDE for easier browsing/analysis) – Thomas Broyer Jul 25 '13 at 09:21

0 Answers0