@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter out = resp.getWriter(); resp.setContentType("text/html"); out.print("<html><head><title>SimpleBVServlet</title></head><body>"); javax.validation.Validator beanValidator = configureValidation(req, resp); out.print("<h1>"); out.print("Validating person class using validateValue with valid property"); out.print("</h1>"); List<String> listOfString = new ArrayList<String>(); listOfString.add("one"); listOfString.add("two"); listOfString.add("three"); Set<ConstraintViolation<Person>> violations = beanValidator.validateValue(Person.class, "listOfString", listOfString); printConstraintViolations(out, violations, "case1"); out.print("<h1>"); out.print("Validating person class using validateValue with invalid property"); out.print("</h1>"); try { violations = beanValidator.validateValue(Person.class, "nonExistentProperty", listOfString); } catch (IllegalArgumentException iae) { out.print("<p>"); out.print("case2: caught IllegalArgumentException. Message: " + iae.getMessage()); out.print("</p>"); } Person person = new Person(); out.print("<h1>"); out.print("Validating invalid person instance using validate."); out.print("</h1>"); violations = beanValidator.validate(person); printConstraintViolations(out, violations, "case3"); out.print("<h1>"); out.print("Validating valid person."); out.print("</h1>"); person.setFirstName("John"); person.setLastName("Yaya"); person.setListOfString(listOfString); violations = beanValidator.validate(person); printConstraintViolations(out, violations, "case4"); out.print("</body></html>"); }
@Override public <T> Set<ConstraintViolation<T>> validateValue( final Class<T> beanType, final String propertyName, final Object value, final Class<?>... groups) { return delegate.validateValue(beanType, propertyName, value, groups); }
/** * 数据验证 * * @param type 类型 * @param property 属性 * @param value 值 * @param groups 验证组 * @return 验证结果 */ protected boolean isValid(Class<?> type, String property, Object value, Class<?>... groups) { Set<?> constraintViolations = validator.validateValue(type, property, value, groups); if (constraintViolations.isEmpty()) { return true; } else { RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes(); requestAttributes.setAttribute( CONSTRAINT_VIOLATIONS_ATTRIBUTE_NAME, constraintViolations, RequestAttributes.SCOPE_REQUEST); return false; } }
@Override public void valueChanged(GraphBacked<T> graphBacked, Object oldVal, Object newVal) { if (validator == null) return; Set<ConstraintViolation<T>> constraintViolations = validator.validateValue((Class<T>) entityType, propertyName, newVal); if (!constraintViolations.isEmpty()) throw new ValidationException( "Error validating field " + propertyName + " of " + entityType + ": " + constraintViolations); }
/** * <span class="changed_modified_2_3">Verify</span> that the value is valid according to the Bean * Validation constraints. <div class="changed_added_2_0"> * * <p>Obtain a {@link ValidatorFactory} instance by calling {@link * javax.validation.Validation#buildDefaultValidatorFactory}. * * <p>Let <em>validationGroupsArray</em> be a <code>Class []</code> representing validator groups * set on the component by the tag handler for this validator. The first search component * terminates the search for the validation groups value. If no such value is found use the class * name of {@link javax.validation.groups.Default} as the value of the validation groups. * * <p>Let <em>valueExpression</em> be the return from calling {@link * UIComponent#getValueExpression} on the argument <em>component</em>, passing the literal string * “value” (without the quotes) as an argument. If this application is running in an * environment with a Unified EL Implementation for Java EE6 or later, obtain the <code> * ValueReference</code> from <em>valueExpression</em> and let <em>valueBaseClase</em> be the * return from calling <code>ValueReference.getBase()</code> and <em>valueProperty</em> be the * return from calling <code>ValueReference.getProperty()</code>. If an earlier version of the * Unified EL is present, use the appropriate methods to inspect <em>valueExpression</em> and * derive values for <em>valueBaseClass</em> and <em>valueProperty</em>. * * <p>If no <code>ValueReference</code> can be obtained, take no action and return. * * <p>If <code>ValueReference.getBase()</code> return <code>null</code>, take no action and * return. * * <p>Obtain the {@link ValidatorContext} from the {@link ValidatorFactory}. * * <p>Decorate the {@link MessageInterpolator} returned from {@link * ValidatorFactory#getMessageInterpolator} with one that leverages the <code>Locale</code> * returned from {@link javax.faces.component.UIViewRoot#getLocale}, and store it in the <code> * ValidatorContext</code> using {@link ValidatorContext#messageInterpolator}. * * <p>Obtain the {@link javax.validation.Validator} instance from the <code>validatorContext * </code>. * * <p>Obtain a <code>javax.validation.BeanDescriptor</code> from the <code> * javax.validation.Validator</code>. If <code>hasConstraints()</code> on the <code>BeanDescriptor * </code> returns false, take no action and return. Otherwise proceed. * * <p>Call {@link javax.validation.Validator#validateValue}, passing <em>valueBaseClass</em>, * <em>valueProperty</em>, the <em>value</em> argument, and <em>validatorGroupsArray</em> as * arguments. * * <p>If the returned <code>Set<{@link * ConstraintViolation}></code> is non-empty, for each element in the <code>Set</code>, create * a {@link FacesMessage} where the summary and detail are the return from calling {@link * ConstraintViolation#getMessage}. Capture all such <code>FacesMessage</code> instances into a * <code>Collection</code> and pass them to {@link * ValidatorException#ValidatorException(java.util.Collection)}. <span * class="changed_added_2_3">If the {@link #ENABLE_VALIDATE_WHOLE_BEAN_PARAM_NAME} application * parameter is enabled and this {@code Validator} instance has validation groups other than or in * addition to the {@code Default} group, record the fact that this field failed validation so * that any <code><f:validateWholeBean /></code> component later in the tree is able to skip * class-level validation for the bean for which this particular field is a property. Regardless * of whether or not {@link #ENABLE_VALIDATE_WHOLE_BEAN_PARAM_NAME} is set, throw the new * exception.</span> * * <p class="changed_added_2_3">If the returned {@code Set} is empty, the {@link * #ENABLE_VALIDATE_WHOLE_BEAN_PARAM_NAME} application parameter is enabled and this {@code * Validator} instance has validation groups other than or in addition to the {@code Default} * group, record the fact that this field passed validation so that any <code> * <f:validateWholeBean /></code> component later in the tree is able to allow class-level * validation for the bean for which this particular field is a property. </div> * * @param context {@inheritDoc} * @param component {@inheritDoc} * @param value {@inheritDoc} * @throws ValidatorException {@inheritDoc} */ @Override public void validate(FacesContext context, UIComponent component, Object value) { if (context == null) { throw new NullPointerException(); } if (component == null) { throw new NullPointerException(); } ValueExpression valueExpression = component.getValueExpression("value"); if (valueExpression == null) { return; } ValidatorFactory validatorFactory; Object cachedObject = context.getExternalContext().getApplicationMap().get(VALIDATOR_FACTORY_KEY); if (cachedObject instanceof ValidatorFactory) { validatorFactory = (ValidatorFactory) cachedObject; } else { try { validatorFactory = Validation.buildDefaultValidatorFactory(); } catch (ValidationException e) { throw new FacesException("Could not build a default Bean Validator factory", e); } context.getExternalContext().getApplicationMap().put(VALIDATOR_FACTORY_KEY, validatorFactory); } ValidatorContext validatorContext = validatorFactory.usingContext(); MessageInterpolator jsfMessageInterpolator = new JsfAwareMessageInterpolator(context, validatorFactory.getMessageInterpolator()); validatorContext.messageInterpolator(jsfMessageInterpolator); javax.validation.Validator beanValidator = validatorContext.getValidator(); Class[] validationGroupsArray = parseValidationGroups(getValidationGroups()); // PENDING(rlubke, driscoll): When EL 1.3 is present, we won't need // this. ValueExpressionAnalyzer expressionAnalyzer = new ValueExpressionAnalyzer(valueExpression); ValueReference valueReference = expressionAnalyzer.getReference(context.getELContext()); if (valueReference == null) { return; } if (isResolvable(valueReference, valueExpression)) { Set<ConstraintViolation<?>> violations = null; try { //noinspection unchecked violations = beanValidator.validateValue( valueReference.getBaseClass(), valueReference.getProperty(), value, validationGroupsArray); } catch (IllegalArgumentException iae) { String failureMessage = "Unable to validate expression " + valueExpression.getExpressionString() + " using Bean Validation. Unable to get value of expression. " + " Message from Bean Validation: " + iae.getMessage(); LOGGER.fine(failureMessage); } if (violations != null && !violations.isEmpty()) { ValidatorException toThrow; if (1 == violations.size()) { ConstraintViolation violation = violations.iterator().next(); toThrow = new ValidatorException( MessageFactory.getMessage( context, MESSAGE_ID, violation.getMessage(), MessageFactory.getLabel(context, component))); } else { Set<FacesMessage> messages = new LinkedHashSet<>(violations.size()); for (ConstraintViolation violation : violations) { messages.add( MessageFactory.getMessage( context, MESSAGE_ID, violation.getMessage(), MessageFactory.getLabel(context, component))); } toThrow = new ValidatorException(messages); } // Record the fact that this field failed validation, so that multi-field // validation is not attempted. if (MultiFieldValidationUtils.wholeBeanValidationEnabled(context, validationGroupsArray)) { Map<Object, Map<String, Map<String, Object>>> multiFieldCandidates = MultiFieldValidationUtils.getMultiFieldValidationCandidates(context, true); Object val = valueReference.getBase(); Map<String, Map<String, Object>> candidate = multiFieldCandidates.getOrDefault(val, new HashMap<>()); Map<String, Object> tuple = new HashMap<>(); tuple.put("component", component); tuple.put("value", FAILED_FIELD_LEVEL_VALIDATION); candidate.put(valueReference.getProperty(), tuple); multiFieldCandidates.putIfAbsent(val, candidate); } throw toThrow; } } // Record the fact that this field passed validation, so that multi-field // validation can be performed if desired if (MultiFieldValidationUtils.wholeBeanValidationEnabled(context, validationGroupsArray)) { Map<Object, Map<String, Map<String, Object>>> multiFieldCandidates = MultiFieldValidationUtils.getMultiFieldValidationCandidates(context, true); Object val = valueReference.getBase(); Map<String, Map<String, Object>> candidate = multiFieldCandidates.getOrDefault(val, new HashMap<>()); Map<String, Object> tuple = new HashMap<>(); // new ComponentValueTuple((EditableValueHolder) component, value); tuple.put("component", component); tuple.put("value", value); candidate.put(valueReference.getProperty(), tuple); multiFieldCandidates.putIfAbsent(val, candidate); } }
@Test public void shouldUnwrapPropertyValuesDuringValueValidation() { Set<ConstraintViolation<Customer>> violations = validator.validateValue(Customer.class, "name", new StringProperty("Bob")); assertEquals(violations.size(), 1); }
@Override public <T> Set<ConstraintViolation<T>> validateValue( Class<T> beanType, String propertyName, Object value, Class<?>... groups) { return validator.validateValue(beanType, propertyName, value, groups); }