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

org.hibernate.validator.engine.ValidationContext Maven / Gradle / Ivy

// $Id$
/*
* JBoss, Home of Professional Open Source
* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,  
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hibernate.validator.engine;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.validation.ConstraintValidatorFactory;
import javax.validation.ConstraintViolation;
import javax.validation.MessageInterpolator;
import javax.validation.TraversableResolver;
import javax.validation.metadata.ConstraintDescriptor;

import org.hibernate.validator.util.IdentitySet;

/**
 * Context object keeping track of all important data for a top level {@link javax.validation.Validator#validate(Object, Class[])} },
 * {@link javax.validation.Validator#validateValue(Class, String, Object, Class[])}  } or {@link javax.validation.Validator#validateProperty(Object, String, Class[])}  call.
 * 

* we use this object to collect all failing constraints, but also to cache the caching traversable resolver for a full stack call. * * @author Hardy Ferentschik * @author Emmanuel Bernard */ public class ValidationContext { /** * The root bean of the validation. */ private final T rootBean; /** * The root bean class of the validation. */ private final Class rootBeanClass; /** * Maps a group to an identity set to keep track of already validated objects. We have to make sure * that each object gets only validated once per group and property path. */ private final Map, IdentitySet> processedObjects; /** * Maps an object to a list of paths in which it has been invalidated. */ private final Map> processedPaths; /** * A list of all failing constraints so far. */ private final List> failingConstraintViolations; /** * Flag indicating whether an object can only be validated once per group or once per group AND validation path. * * @todo Make this boolean a configurable item. */ private boolean allowOneValidationPerPath = true; /** * The message resolver which should be used in this context. */ private final MessageInterpolator messageInterpolator; /** * The constraint factory which should be used in this context. */ private final ConstraintValidatorFactory constraintValidatorFactory; /** * Allows a JPA provider to decide whether a property should be validated. */ private final TraversableResolver traversableResolver; public static ValidationContext getContextForValidate(T object, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) { @SuppressWarnings("unchecked") Class rootBeanClass = ( Class ) object.getClass(); return new ValidationContext( rootBeanClass, object, messageInterpolator, constraintValidatorFactory, traversableResolver ); } public static ValidationContext getContextForValidateProperty(T rootBean, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) { @SuppressWarnings("unchecked") Class rootBeanClass = ( Class ) rootBean.getClass(); return new ValidationContext( rootBeanClass, rootBean, messageInterpolator, constraintValidatorFactory, traversableResolver ); } public static ValidationContext getContextForValidateValue(Class rootBeanClass, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) { return new ValidationContext( rootBeanClass, null, messageInterpolator, constraintValidatorFactory, traversableResolver ); } private ValidationContext(Class rootBeanClass, T rootBean, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) { this.rootBean = rootBean; this.rootBeanClass = rootBeanClass; this.messageInterpolator = messageInterpolator; this.constraintValidatorFactory = constraintValidatorFactory; this.traversableResolver = traversableResolver; processedObjects = new HashMap, IdentitySet>(); processedPaths = new IdentityHashMap>(); failingConstraintViolations = new ArrayList>(); } public T getRootBean() { return rootBean; } public Class getRootBeanClass() { return rootBeanClass; } public TraversableResolver getTraversableResolver() { return traversableResolver; } public MessageInterpolator getMessageInterpolator() { return messageInterpolator; } public ConstraintViolationImpl createConstraintViolation(ValueContext localContext, MessageAndPath messageAndPath, ConstraintDescriptor descriptor) { String messageTemplate = messageAndPath.getMessage(); String interpolatedMessage = messageInterpolator.interpolate( messageTemplate, new MessageInterpolatorContext( descriptor, localContext.getCurrentValidatedValue() ) ); return new ConstraintViolationImpl( messageTemplate, interpolatedMessage, getRootBeanClass(), getRootBean(), localContext.getCurrentBean(), localContext.getCurrentValidatedValue(), messageAndPath.getPath(), descriptor, localContext.getElementType() ); } public List> createConstraintViolations(ValueContext localContext, ConstraintValidatorContextImpl constraintValidatorContext) { List> constraintViolations = new ArrayList>(); for ( MessageAndPath messageAndPath : constraintValidatorContext.getMessageAndPathList() ) { ConstraintViolationImpl violation = createConstraintViolation( localContext, messageAndPath, constraintValidatorContext.getConstraintDescriptor() ); constraintViolations.add( violation ); } return constraintViolations; } public ConstraintValidatorFactory getConstraintValidatorFactory() { return constraintValidatorFactory; } public boolean isAlreadyValidated(Object value, Class group, PathImpl path) { boolean alreadyValidated; alreadyValidated = isAlreadyValidatedForCurrentGroup( value, group ); if ( alreadyValidated && allowOneValidationPerPath ) { alreadyValidated = isAlreadyValidatedForPath( value, path ); } return alreadyValidated; } public void markProcessed(Object value, Class group, PathImpl path) { markProcessForCurrentGroup( value, group ); if ( allowOneValidationPerPath ) { markProcessedForCurrentPath( value, path ); } } private void addConstraintFailure(ConstraintViolation failingConstraintViolation) { // NOTE: we are relying on the fact that ConstraintViolation.equals() is implemented correctly. int i = failingConstraintViolations.indexOf( failingConstraintViolation ); if ( i == -1 ) { failingConstraintViolations.add( failingConstraintViolation ); } } public void addConstraintFailures(List> failingConstraintViolations) { for ( ConstraintViolation violation : failingConstraintViolations ) { addConstraintFailure( violation ); } } public List> getFailingConstraints() { return failingConstraintViolations; } private boolean isAlreadyValidatedForPath(Object value, PathImpl path) { Set pathSet = processedPaths.get( value ); if ( pathSet == null ) { return false; } for ( PathImpl p : pathSet ) { if ( p.isRootPath() || path.isRootPath() || p.isSubPathOf( path ) || path.isSubPathOf( p ) ) { return true; } } return false; } private boolean isAlreadyValidatedForCurrentGroup(Object value, Class group) { final IdentitySet objectsProcessedInCurrentGroups = processedObjects.get( group ); return objectsProcessedInCurrentGroups != null && objectsProcessedInCurrentGroups.contains( value ); } private void markProcessedForCurrentPath(Object value, PathImpl path) { // hmm - not sure if the current definiton of Path and Node are consistent. Shouldn't a simple property // of a entity have a parent node? PathImpl parentPath = path.getPathWithoutLeafNode(); if ( parentPath == null ) { parentPath = PathImpl.createNewPath( null ); } if ( processedPaths.containsKey( value ) ) { processedPaths.get( value ).add( parentPath ); } else { Set set = new HashSet(); set.add( parentPath ); processedPaths.put( value, set ); } } private void markProcessForCurrentGroup(Object value, Class group) { if ( processedObjects.containsKey( group ) ) { processedObjects.get( group ).add( value ); } else { IdentitySet set = new IdentitySet(); set.add( value ); processedObjects.put( group, set ); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy