0

I want to perform inline validation on the fields in a form, using JSR-303. By inline (aka on-the-fly) validation, I mean that each field is validated as the user works through the form (e.g. on blur or on key press), as opposed to deferring validation until a submit button is pressed. Typically, error messages are displayed near the input field.

I'm following the procedures described in GWT validation dev guide where an example shows JSR-303 constraints being defined for the fields (in this case just one field, name) in a Person class:

// Copied from http://www.gwtproject.org/doc/latest/DevGuideValidation.html
public class Person implements Serializable {
  @NotNull
  @Size(min = 4, message = "Name must be at least 4 characters long.")
  private String name;
} 

The class(es) (just Person in this case) to be validated are specified like this:

// Copied from http://www.gwtproject.org/doc/latest/DevGuideValidation.html
public final class MyValidatorFactory extends AbstractGwtValidatorFactory {
  /**
   * Validator marker for the Validation Sample project. Only the classes and groups listed
   * in the {@link GwtValidation} annotation can be validated.
   */
  @GwtValidation(Person.class)
  public interface GwtValidator extends Validator {
  } 
  @Override
  public AbstractGwtValidator createValidator() {
    return GWT.create(GwtValidator.class);
  }
}

Suppose I have a TextBox on which I want to perform inline validation. I attempt to define constraints like this:

// Example of code that does not work!
import com.google.gwt.user.client.ui.TextBox;
import javax.validation.constraints.Pattern;
public class FooWidget extends TextBox {
  @Pattern(regexp="^[0-9]+$", message="Foo: expected digits.")
  public String getFoo() { 
    return getValue(); // from TextBox
  }
}

with the corresponding definition in MyValidatorFactory:

// Example of code that does not work!
@GwtValidation(FooWidget.class)
public interface GwtValidator extends Validator {
}

However, this does not compile (I'm using GWT 2.7.0), producing the following errors:

   [ERROR] An internal compiler exception occurred
com.google.gwt.dev.jjs.InternalCompilerException: Unexpected error during visit.
    at com.google.gwt.dev.jjs.ast.JVisitor.translateException(JVisitor.java:121)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:296)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:285)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:128)
    at com.google.gwt.dev.jjs.ast.JCastOperation.traverse(JCastOperation.java:67)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:381)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:293)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:285)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:128)
    at com.google.gwt.dev.jjs.ast.JDeclarationStatement.traverse(JDeclarationStatement.java:49)
    at com.google.gwt.dev.jjs.ast.JModVisitor$ListContext.traverse(JModVisitor.java:95)
    at com.google.gwt.dev.jjs.ast.JModVisitor.acceptWithInsertRemove(JModVisitor.java:351)
    at com.google.gwt.dev.jjs.ast.JBlock.traverse(JBlock.java:92)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:381)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:293)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:149)
    at com.google.gwt.dev.jjs.ast.JVisitor.accept(JVisitor.java:145)
    at com.google.gwt.dev.jjs.ast.JMethodBody.traverse(JMethodBody.java:83)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:381)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:293)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:285)
    at com.google.gwt.dev.jjs.ast.JMethod.visitChildren(JMethod.java:600)
    at com.google.gwt.dev.jjs.ast.JMethod.traverse(JMethod.java:569)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:381)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:293)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:285)
    at com.google.gwt.dev.jjs.impl.UnifyAst.mainLoop(UnifyAst.java:1505)
    at com.google.gwt.dev.jjs.impl.UnifyAst.exec(UnifyAst.java:870)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler$Precompiler.unifyJavaAst(JavaToJavaScriptCompiler.java:1305)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler$Precompiler.constructJavaAst(JavaToJavaScriptCompiler.java:1038)
    at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler$Precompiler.precompile(JavaToJavaScriptCompiler.java:954)
    at com.google.gwt.dev.jjs.MonolithicJavaToJavaScriptCompiler.precompile(MonolithicJavaToJavaScriptCompiler.java:303)
    at com.google.gwt.dev.jjs.JavaScriptCompiler.precompile(JavaScriptCompiler.java:38)
    at com.google.gwt.dev.Precompile.precompile(Precompile.java:286)
    at com.google.gwt.dev.Precompile.precompile(Precompile.java:229)
    at com.google.gwt.dev.Precompile.precompile(Precompile.java:145)
    at com.google.gwt.dev.Compiler.run(Compiler.java:206)
    at com.google.gwt.dev.codeserver.Recompiler.doCompile(Recompiler.java:333)
    at com.google.gwt.dev.codeserver.Recompiler.compile(Recompiler.java:161)
    at com.google.gwt.dev.codeserver.Recompiler.recompile(Recompiler.java:119)
    at com.google.gwt.dev.codeserver.Outbox.recompile(Outbox.java:128)
    at com.google.gwt.dev.codeserver.JobRunner.recompile(JobRunner.java:81)
    at com.google.gwt.dev.codeserver.JobRunner.access$100(JobRunner.java:34)
    at com.google.gwt.dev.codeserver.JobRunner$2.run(JobRunner.java:73)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NoClassDefFoundError: Could not initialize class com.myco.myapp.FooWidget
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:260)
    at com.google.gwt.validation.rebind.BeanHelperCache.createHelper(BeanHelperCache.java:85)
    at com.google.gwt.validation.rebind.ValidatorGenerator.generateGwtSpecificValidator(ValidatorGenerator.java:131)
    at com.google.gwt.validation.rebind.ValidatorGenerator.generate(ValidatorGenerator.java:67)
    at com.google.gwt.core.ext.IncrementalGenerator.generateNonIncrementally(IncrementalGenerator.java:40)
    at com.google.gwt.dev.javac.StandardGeneratorContext.runGeneratorIncrementally(StandardGeneratorContext.java:760)
    at com.google.gwt.dev.cfg.RuleGenerateWith.realize(RuleGenerateWith.java:160)
    at com.google.gwt.dev.shell.StandardRebindOracle$Rebinder.rebind(StandardRebindOracle.java:79)
    at com.google.gwt.dev.shell.StandardRebindOracle.rebind(StandardRebindOracle.java:276)
    at com.google.gwt.dev.shell.StandardRebindOracle.rebind(StandardRebindOracle.java:265)
    at com.google.gwt.dev.DistillerRebindPermutationOracle.getAllPossibleRebindAnswers(DistillerRebindPermutationOracle.java:87)
    at com.google.gwt.dev.jjs.impl.UnifyAst$UnifyVisitor.createStaticRebindExpression(UnifyAst.java:485)
    at com.google.gwt.dev.jjs.impl.UnifyAst$UnifyVisitor.createRebindExpression(UnifyAst.java:443)
    at com.google.gwt.dev.jjs.impl.UnifyAst$UnifyVisitor.handleMagicMethodCall(UnifyAst.java:576)
    at com.google.gwt.dev.jjs.impl.UnifyAst$UnifyVisitor.endVisit(UnifyAst.java:306)
    at com.google.gwt.dev.jjs.ast.JMethodCall.traverse(JMethodCall.java:248)
    at com.google.gwt.dev.jjs.ast.JModVisitor.traverse(JModVisitor.java:381)
    at com.google.gwt.dev.jjs.ast.JModVisitor.accept(JModVisitor.java:293)
    ... 47 more
      [ERROR] at _FooWidgetValidator.java(6): GWT.create(_FooWidgetValidator.class)
         com.google.gwt.dev.jjs.ast.JMethodCall
      [ERROR] at _FooWidgetValidator.java(6): (_FooWidgetValidator) GWT.create(_FooWidgetValidator.class)
         com.google.gwt.dev.jjs.ast.JCastOperation
      [ERROR] at _FooWidgetValidator.java(6): final static _FooWidgetValidator INSTANCE = (_FooWidgetValidator) GWT.create(_FooWidgetValidator.class)
         com.google.gwt.dev.jjs.ast.JDeclarationStatement
      [ERROR] at _FooWidgetValidator.java(5): {
  final static _FooWidgetValidator INSTANCE = (_FooWidgetValidator) GWT.create(_FooWidgetValidator.class);
}
         com.google.gwt.dev.jjs.ast.JBlock
      [ERROR] at _FooWidgetValidator.java(5): {
  final static _FooWidgetValidator INSTANCE = (_FooWidgetValidator) GWT.create(_FooWidgetValidator.class);
}
         com.google.gwt.dev.jjs.ast.JMethodBody
      [ERROR] at _FooWidgetValidator.java(5): private static final void $clinit();

         com.google.gwt.dev.jjs.ast.JMethod
[ERROR] Compiler returned false

What's going on here and why doesn't this work?

The error messages refer to generated source code. I'd like to know how to relate them to my source code. Without understanding exactly what is broken, one resorts to experimental changes in search of a fix :-( .

One of those experimental changes has produced something that seems to work. I've posted another question about that: Inline validation using JSR-303 in GWT, part 2: A good implementation?, so if want to suggest how to do inline validation, maybe look at that question. This question is about understanding why the approach of putting constraints inside my FooWidget does not work.

One further detail: I know that the class to be validated should implement Serializable, as not to do so means it isn't a Java Bean. But there are plenty of examples on the web where that hasn't been done. Does it matter?

Community
  • 1
  • 1
Matt Wallis
  • 873
  • 5
  • 25

1 Answers1

1
Caused by: java.lang.NoClassDefFoundError: Could not initialize class com.myco.myapp.FooWidget

You have to compile (javac) your classes before calling the GWT Compiler (and put them in its classpath).

(note: the GWT validation generator should probably try to load the class from GWT's internal TypeOracle rather than from the classloader; also note that GWT-Validation support is almost unmaintained – someone recently volunteered to maintain it, but hasn't contributed much yet)

Thomas Broyer
  • 64,353
  • 7
  • 91
  • 164
  • Thank you, Thomas. I don't know how to introduce that `javac` step into our build process. Our project uses the GWT maven archetypes from https://github.com/tbroyer/gwt-maven-archetypes, and we use `mvn gwt:run -Ddev`, and then the new (GWT2.7.0) incremental GWT compiler. Any help on this much appreciated. – Matt Wallis Nov 27 '14 at 13:46
  • From your note, Thomas, it sounds as if it may be unwise to embark on using GWT-Validation right now :-( – Matt Wallis Nov 27 '14 at 13:52
  • Hmm, things are supposed to work with my archetypes… As for GWT-Validation, unless you'd accept debugging and contributing back patches, I wouldn't start using it –but I'm not found of JSR 303 to begin with– (that said, people –and big companies I believe– are using it, and we've had a few marks of interest in maintaining it; no real/visible commitment yet though) – Thomas Broyer Nov 27 '14 at 15:01