How to use the GWT editor framework for validation

2019-02-03 07:59发布

问题:

I am trying to integrate with the new GWT Editor framework of GWT 2.1.0. I also want to add my validation checks into the framework. However, I am struggling to find a decent example how to do this.

For the moment I have the following code:

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
    xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:e="urn:import:com.google.gwt.editor.ui.client">
    <ui:with type="be.credoc.iov.webapp.client.MessageConstants"
        field="msg" />
    <g:HTMLPanel>
        <e:ValueBoxEditorDecorator ui:field="personalReference">
            <e:valuebox>
                <g:TextBox />
            </e:valuebox>
        </e:ValueBoxEditorDecorator>
    </g:HTMLPanel>
</ui:UiBinder> 

And for my editor:

public class GarageEditor extends Composite implements Editor<Garage> {

    @UiField
    ValueBoxEditorDecorator<String> personalReference;

    interface GarageEditorUiBinder extends UiBinder<Widget, GarageEditor> {
    }

    private static GarageEditorUiBinder uiBinder = GWT.create(GarageEditorUiBinder.class);

    public GarageEditor() {
        initWidget(uiBinder.createAndBindUi(this));
    }

}

On what point do I have to call my validator and how do I integrate with it?

Update:

I am actually looking for a way to retrieve a map with as key the property path, and as value the editor. There is a path field on a delegate, but this is not the path within the edited object, but the path in the editor class.

Does anybody know if it is possible to do something like this?

回答1:

Annotate you beans with contstrants (see Person.java)

public class Person {
  @Size(min = 4)
  private String name;
}

Use the standard validation bootstrap to get a Validator on the client and validate your object (see ValidationView.java)

Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<Person>> violations = validator.validate(person);

Follow this pattern to create a Validator for the objects you want to validate on the client. (see SampleValidatorFactory.java)

public final class SampleValidatorFactory extends AbstractGwtValidatorFactory {

  /**
   * Validator marker for the Validation Sample project. Only the classes listed
   * in the {@link GwtValidation} annotation can be validated.
   */
  @GwtValidation(value = Person.class,
      groups = {Default.class, ClientGroup.class})
  public interface GwtValidator extends Validator {
  }

  @Override
  public AbstractGwtValidator createValidator() {
    return GWT.create(GwtValidator.class);
  }
}

Include the module for your Validation Provider. Add replace-with tag in your gwt modle file telling GWT to use the Validator you just defined (see Validation.gwt.xml)

<inherits name="org.hibernate.validator.HibernateValidator" />
<replace-with
    class="com.google.gwt.sample.validation.client.SampleValidatorFactory">
    <when-type-is class="javax.validation.ValidatorFactory" />
</replace-with>

Source



回答2:

I have done something similar to this by adding an additional DriverWrapper class that takes the existing Driver and Validator and adds a flush method that first delegates to the underlying Driver flush and then calls the Validator. Any errors returned are then added to the Editors using a new visitor, similar to the way the existing Flusher works. This means the existing decorators that display the errors next to the fields continue to work.

/**
 * Wraps a Driver and provides validation using gwt-validation (JSR 303).
 * When calling flush, this will use the provided IValidator to validate the data
 * and use the InvalidConstraintValidationVisitor to add the errors to the delegates.
 * @see InvalidConstraintValidationVisitor
 * @param <T> the data type for the editor
 * @param <D> the driver type
 */
public class ValidationDriverWrapper<T extends IsValidatable<T>, D extends EditorDriver<T>> {
private IValidator<T> validator;
private D driver;

/**
 * Constructor, both parameters are required.
 * @param driver The driver to use to flush the underlying data.
 * @param validator The validator to use to validate the data.
 */
public ValidationDriverWrapper(D driver, IValidator<T> validator) {
    this.validator = validator;
    this.driver = driver;
}

/**
 * Flushes the underlying Driver and then calls the validation on the underlying Validator, cascading errors as EditorErrors
 * onto the delegates, using InvalidContraintValidationVisitor.
 */
public void flush()
{
    T data = driver.flush();
    Set<InvalidConstraint<T>> errors = validator.validate(data);
    Set<InvalidConstraint<T>> extraErrors = data.validate();
    if(extraErrors != null && !extraErrors.isEmpty())
    {
        errors.addAll(extraErrors);
    }
    driver.accept(new InvalidConstraintValidationVisitor<T>(errors));
}


回答3:

I've got exaclty the same problem.

The documentation is not clear about it.

What I'm currently doing is to recreate some widgets by extending them with widget I want to copy. After it I implement LeafValueEditor and HasEditorDelegate to override getValue().

In getValue(), use your validator and call if needed yourDelegate.recordError().

Something like this: a little integer box which check that value is not greater than 10.

public class IntegerField extends ValueBox<Integer> implements LeafValueEditor<Integer>, HasEditorDelegate<Integer>
{
private EditorDelegate<Integer> delegate;

public IntegerField()
{
    super(Document.get().createTextInputElement(), IntegerRenderer.instance(), IntegerParser.instance());

    setStyleName("gwt-TextBox");

}

@Override
public Integer getValue()
{
    Integer value = super.getValue();

    if (value > 10)
    {
        delegate.recordError("too big integer !", value, null);
    }

    return value;
}

@Override
public void setValue(Integer value)
{
    super.setValue(value);
}

@Override
public void setDelegate(EditorDelegate<Integer> delegate)
{
    this.delegate = delegate;
}
}

The best approach is to simply add custom verification to existing widgets and not override them but I don't know how to do it !



回答4:

Validation doesn't exist in GWT yet, it's coming in the next release AFAIK. The current support for validation in GWT is server side JSR-303 and client side JSR-303 support is coming soon. Therefore, you'll have to do the validation manually. If you follow the MVP model, I think this validation logic would live in your Presenter.



回答5:

It's messy but to get the path of an Editor you could implement HasEditorDelegate (which will give you access to the delegate) and then cast the Delegate to AbstractEditorDelegate, which has a public String getPath() method.

I don't think it is possible to do external validation though; validation happens in the editor at the point that a value is read from the field (see ValueBoxEditor - this editor uses getDelegate().recordError to raise an error). One option I did consider was to use the AbstractEditorDelegate access to call flushErrors(List) and to create that list of EditorErrors myself. To do that you need to know each of your field paths; hardcoding them is hardly desirable, but I don't see a way of looking up the Field by the edited property or anything like that.

An alternative approach that might bear looking into is this submission for round trip validation using the requestfactory:

http://groups.google.com/group/google-web-toolkit-contributors/browse_thread/thread/5be0bda80547ca5a