All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vaadin.data.validator.BeanValidator Maven / Gradle / Ivy

There is a newer version: 8.27.3
Show newest version
/*
 * Copyright (C) 2000-2024 Vaadin Ltd
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See  for the full
 * license.
 */

package com.vaadin.data.validator;

import java.io.Serializable;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.MessageInterpolator.Context;
import javax.validation.Validation;
import javax.validation.ValidatorFactory;
import javax.validation.metadata.ConstraintDescriptor;

import com.vaadin.data.ValidationResult;
import com.vaadin.data.Validator;
import com.vaadin.data.ValueContext;
import com.vaadin.data.util.BeanUtil;

/**
 * A {@code Validator} using the JSR-303 (javax.validation) annotation-based
 * bean validation mechanism. Values passed to this validator are compared
 * against the constraints, if any, specified by annotations on the
 * corresponding bean property.
 * 

* Note that a JSR-303 implementation (for instance * Hibernate Validator or * Apache BVal) must be present on the * project classpath when using bean validation. Specification versions 1.0 and * 1.1 are supported. * * @author Vaadin Ltd. * * @since 8.0 */ public class BeanValidator implements Validator { private static final class ContextImpl implements Context, Serializable { private final ConstraintViolation violation; private ContextImpl(ConstraintViolation violation) { this.violation = violation; } @Override public ConstraintDescriptor getConstraintDescriptor() { return violation.getConstraintDescriptor(); } @Override public Object getValidatedValue() { return violation.getInvalidValue(); } @Override public T unwrap(Class type) { return violation.unwrap(type); } } private String propertyName; private Class beanType; /** * Creates a new JSR-303 {@code BeanValidator} that validates values of the * specified property. Localizes validation messages using the * {@linkplain Locale#getDefault() default locale}. * * @param beanType * the bean type declaring the property, not null * @param propertyName * the property to validate, not null * @throws IllegalStateException * if {@link BeanUtil#checkBeanValidationAvailable()} returns * false */ public BeanValidator(Class beanType, String propertyName) { if (!BeanUtil.checkBeanValidationAvailable()) { throw new IllegalStateException("Cannot create a " + BeanValidator.class.getSimpleName() + ": a JSR-303 Bean Validation implementation not found on the classpath"); } Objects.requireNonNull(beanType, "bean class cannot be null"); Objects.requireNonNull(propertyName, "property name cannot be null"); this.beanType = beanType; this.propertyName = propertyName; } /** * Validates the given value as if it were the value of the bean property * configured for this validator. Returns {@code Result.ok} if there are no * JSR-303 constraint violations, a {@code Result.error} of chained * constraint violation messages otherwise. *

* Null values are accepted unless the property has an {@code @NotNull} * annotation or equivalent. * * @param value * the input value to validate * @param context * the value context for validation * @return the validation result */ @Override public ValidationResult apply(final Object value, ValueContext context) { Set> violations = getJavaxBeanValidator() .validateValue(beanType, propertyName, value); Locale locale = context.getLocale().orElse(Locale.getDefault()); Optional result = violations.stream() .map(violation -> ValidationResult .error(getMessage(violation, locale))) .findFirst(); return result.orElse(ValidationResult.ok()); } @Override public String toString() { return String.format("%s[%s.%s]", getClass().getSimpleName(), beanType.getSimpleName(), propertyName); } /** * Returns the underlying JSR-303 bean validator factory used. A factory is * created using {@link Validation} if necessary. * * @return the validator factory to use */ protected static ValidatorFactory getJavaxBeanValidatorFactory() { return LazyFactoryInitializer.FACTORY; } /** * Returns a shared JSR-303 validator instance to use. * * @return the validator to use */ public javax.validation.Validator getJavaxBeanValidator() { return getJavaxBeanValidatorFactory().getValidator(); } /** * Returns the interpolated error message for the given constraint violation * using the locale specified for this validator. * * @param violation * the constraint violation * @param locale * the used locale * @return the localized error message */ protected String getMessage(ConstraintViolation violation, Locale locale) { return getJavaxBeanValidatorFactory().getMessageInterpolator() .interpolate(violation.getMessageTemplate(), createContext(violation), locale); } /** * Creates a simple message interpolation context based on the given * constraint violation. * * @param violation * the constraint violation * @return the message interpolation context */ protected Context createContext(ConstraintViolation violation) { return new ContextImpl(violation); } private static class LazyFactoryInitializer implements Serializable { private static final ValidatorFactory FACTORY = getFactory(); private static ValidatorFactory getFactory() { return Validation.buildDefaultValidatorFactory(); } private LazyFactoryInitializer() { } } }