Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Eclipse Platform » Databinding: Validation and JSR303 / How to use ValidationStatusProvider
Databinding: Validation and JSR303 / How to use ValidationStatusProvider [message #484565] Tue, 08 September 2009 09:20 Go to next message
Marcus Ilgner is currently offline Marcus Ilgner
Messages: 15
Registered: July 2009
Junior Member
This is a multi-part message in MIME format.
--------------050408020003020203070902
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Hi all,

after stumbling upon the upcoming JSR303
(http://jcp.org/en/jsr/detail?id=303) standard for bean validation last
week, I decided that I liked the approach and spent a bit of time of my
weekend to write some code to use it from a validator in Eclipse.
It already works for simple properties (see attached JSR303Validator
class, it's EPL so feel free to use it in your code).

Now come the tricky bits though and I'd like to get some feedback from
you Eclipse validation gurus out there:
Whereas JSR303 runs validation on properties already set on the beans
(excepting validateValue, which I use in the validator), Eclipse
Databinding runs the IValidator before the setter gets called at the latest.
Now there may be constraints which aren't focussed on a single property
but concern the whole object. I'll want to check my object against those
constraints somehow.
And while I could just register a custom PropertyChangeListener on the
object and trigger some action like disabling the save action or a
wizards "next" button, I'd like to remain within the context of databinding.
My guess is that ValidationStatusProvider was meant for this sort of
thing but after looking at the API documentation and trying to use
MultiValidator for a bit, I'm a bit stuck on this issue.
Does someone have an example on how to use this thing? I'd be grateful
for any hints.

Best regards
Marcus

--------------050408020003020203070902
Content-Type: text/plain;
name="JSR303Validator.java"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="JSR303Validator.java"

package com.marcusilgner.research.validation;

import java.util.Iterator;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.ValidationException;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.databinding.validation.ValidationStatus;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Control;

/**
* A Eclipse Databinding Validator implementation which uses the JSR303
* validation API to check a single property for validity. Use as
* beforeSetValidator, after the value has been converted to the targets
* property class
*
* Licensed under EPL v1.0 (http://www.eclipse.org/legal/epl-v10.html)
*
* To use, initialize JSR303 first and call setValidatorFactory
*
* If given a control, this validator will also paint a field decoration
*
* @author Marcus Ilgner <mail@marcusilgner.com>
*
* @param <T>
* The class of the bean being bound. Not actively used as
* {@link javax.validation.Validator#validateValue(Class, String, Object, Class...)}
* works somewhat differently than
* {@link javax.validation.Validator#validateProperty(Object, String, Class...)}
* Should the API be frozen like this, the template class will
* probably removed
*/
public class JSR303Validator<T extends Object> implements IValidator {

// the bean to be validated
private T bean;

// the name of the bean property to check
private String propertyName;

// a validator to run validation against
private Validator validator;

// will show a field decoration if validation constraints are violated
private ControlDecoration controlDecoration;

// a shared validator factory to be used by all instances of this class
private static ValidatorFactory validatorFactory;

/**
* initializes the validator with a non-default
* javax.validation.ValidatorFactory
*
* @param _factory
*/
public static void setValidatorFactory(ValidatorFactory _factory) {
validatorFactory = _factory;
}

/**
* simple constructor which doesn't use field decorations JSR303Validator(T,
* String, Control) is recommended
*
* @param _bean
* the bean to validate
* @param _propertyName
* name of the property to be validated
*/
public JSR303Validator(T _bean, String _propertyName) {
bean = _bean;
propertyName = _propertyName;

controlDecoration = null;
initValidator();
}

/**
* constructor which constructs a field decoration on the specified control
*
* @param _bean
* the bean to validate
* @param _propertyName
* name of the property to be validated
* @param _control
* control to receive field decoration on constraint violation
*/
public JSR303Validator(T _bean, String _propertyName, Control _control) {
bean = _bean;
propertyName = _propertyName;
initValidator();
createFieldDecoration(_control);
}

/**
* Creates a field decoration on the given control
*
* @param _control
* control to be decorated
*/
private void createFieldDecoration(Control _control) {
controlDecoration = new ControlDecoration(_control, SWT.LEFT
| SWT.BOTTOM);
FieldDecoration fieldDecoration = FieldDecorationRegistry.getDefault()
.getFieldDecoration(FieldDecorationRegistry.DEC_ERROR);
controlDecoration.setImage(fieldDecoration.getImage());
}

/**
* Creates a validator. If no javax.validation.ValidatorFactory was set it
* will try to create a factory from defaults
*/
private void initValidator() {
if (validatorFactory == null) {
// JSR303 hasn't been initialized. Give it a shot.
try {
validatorFactory = Validation.buildDefaultValidatorFactory();
} catch (Exception e) {
throw new ValidationException(
"ValidationFactory not set and unable to initialize validation from default values");
}
}
validator = validatorFactory.getValidator();

}

/**
* runs the actual validation and shows the decoration if required
*/
@Override
public IStatus validate(Object _value) {
Set<?> validationResult = validator.validateValue(bean.getClass(),
propertyName, _value, javax.validation.groups.Default.class);
if (validationResult.size() > 0) {
String message = assembleErrorMessage(validationResult);
if (controlDecoration != null) {
controlDecoration.setDescriptionText(message);
controlDecoration.show();
}
return ValidationStatus.error(message);
}
if (controlDecoration != null) {
controlDecoration.hide();
}
return ValidationStatus.ok();
}

/**
* Concatenates the messages from the validationResult into a single
* multi-line string
*
* @param validationResult
* a result from calling a JSR303 validation method
* @return
*/
@SuppressWarnings("unchecked")
private String assembleErrorMessage(Set<?> validationResult) {
String message = "";
Iterator<ConstraintViolation> iterator = (Iterator<ConstraintViolation>) validationResult
.iterator();
while (iterator.hasNext()) {
ConstraintViolation violation = iterator.next();
message += violation.getMessage();
if (iterator.hasNext()) {
message += System.getProperty("line.separator");
}
}
return message;
}

}

--------------050408020003020203070902--
Re: Databinding: Validation and JSR303 / How to use ValidationStatusProvider [message #485519 is a reply to message #484565] Sat, 12 September 2009 13:29 Go to previous messageGo to next message
Thomas Schindl is currently offline Thomas Schindl
Messages: 5321
Registered: July 2009
Senior Member
You need to attach a MultiValidator to the DatabindingContext.

Tom

Marcus Ilgner schrieb:
> Hi all,
>
> after stumbling upon the upcoming JSR303
> (http://jcp.org/en/jsr/detail?id=303) standard for bean validation last
> week, I decided that I liked the approach and spent a bit of time of my
> weekend to write some code to use it from a validator in Eclipse.
> It already works for simple properties (see attached JSR303Validator
> class, it's EPL so feel free to use it in your code).
>
> Now come the tricky bits though and I'd like to get some feedback from
> you Eclipse validation gurus out there:
> Whereas JSR303 runs validation on properties already set on the beans
> (excepting validateValue, which I use in the validator), Eclipse
> Databinding runs the IValidator before the setter gets called at the
> latest.
> Now there may be constraints which aren't focussed on a single property
> but concern the whole object. I'll want to check my object against those
> constraints somehow.
> And while I could just register a custom PropertyChangeListener on the
> object and trigger some action like disabling the save action or a
> wizards "next" button, I'd like to remain within the context of
> databinding.
> My guess is that ValidationStatusProvider was meant for this sort of
> thing but after looking at the API documentation and trying to use
> MultiValidator for a bit, I'm a bit stuck on this issue.
> Does someone have an example on how to use this thing? I'd be grateful
> for any hints.
>
> Best regards
> Marcus
>
Re: Databinding: Validation and JSR303 / How to use ValidationStatusProvider [message #485520 is a reply to message #485519] Sat, 12 September 2009 13:35 Go to previous message
Thomas Schindl is currently offline Thomas Schindl
Messages: 5321
Registered: July 2009
Senior Member
Maybe you want to further discuss such an implementation on the platform
level in bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=279166.

Tom

Tom Schindl schrieb:
> You need to attach a MultiValidator to the DatabindingContext.
>
> Tom
>
> Marcus Ilgner schrieb:
>> Hi all,
>>
>> after stumbling upon the upcoming JSR303
>> (http://jcp.org/en/jsr/detail?id=303) standard for bean validation last
>> week, I decided that I liked the approach and spent a bit of time of my
>> weekend to write some code to use it from a validator in Eclipse.
>> It already works for simple properties (see attached JSR303Validator
>> class, it's EPL so feel free to use it in your code).
>>
>> Now come the tricky bits though and I'd like to get some feedback from
>> you Eclipse validation gurus out there:
>> Whereas JSR303 runs validation on properties already set on the beans
>> (excepting validateValue, which I use in the validator), Eclipse
>> Databinding runs the IValidator before the setter gets called at the
>> latest.
>> Now there may be constraints which aren't focussed on a single property
>> but concern the whole object. I'll want to check my object against those
>> constraints somehow.
>> And while I could just register a custom PropertyChangeListener on the
>> object and trigger some action like disabling the save action or a
>> wizards "next" button, I'd like to remain within the context of
>> databinding.
>> My guess is that ValidationStatusProvider was meant for this sort of
>> thing but after looking at the API documentation and trying to use
>> MultiValidator for a bit, I'm a bit stuck on this issue.
>> Does someone have an example on how to use this thing? I'd be grateful
>> for any hints.
>>
>> Best regards
>> Marcus
>>
Previous Topic:TreeViewer with lazy loading
Next Topic:Undo Manager Highlights?
Goto Forum:
  


Current Time: Wed Sep 17 09:38:03 GMT 2014

Powered by FUDForum. Page generated in 0.02242 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software