Eclipse Community Forums - RDF feed
https://www.eclipse.org/forums/
Eclipse Community ForumsDatabinding: Validation and JSR303 / How to use ValidationStatusProvider
https://www.eclipse.org/forums/index.php/mv/msg/153857/484565/#msg_484565
--------------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.
/**
* 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--]]>Marcus Ilgner2009-09-08T09:20:40-00:00Re: Databinding: Validation and JSR303 / How to use ValidationStatusProvider
https://www.eclipse.org/forums/index.php/mv/msg/153857/485519/#msg_485519
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
>]]>Thomas Schindl2009-09-12T13:29:50-00:00Re: Databinding: Validation and JSR303 / How to use ValidationStatusProvider
https://www.eclipse.org/forums/index.php/mv/msg/153857/485520/#msg_485520
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
>>]]>Thomas Schindl2009-09-12T13:35:57-00:00