/*
 * Hibernate Validator, declare and validate application constraints
 *
 * License: Apache License, Version 2.0
 * See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
 */
package org.hibernate.validator.internal.metadata.aggregated;

import java.lang.invoke.MethodHandles;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.validation.metadata.GroupConversionDescriptor;

import org.hibernate.validator.internal.engine.valueextraction.AnnotatedObject;
import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorDescriptor;
import org.hibernate.validator.internal.engine.valueextraction.ValueExtractorManager;
import org.hibernate.validator.internal.util.CollectionHelper;
import org.hibernate.validator.internal.util.StringHelper;
import org.hibernate.validator.internal.util.TypeVariables;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;
import org.hibernate.validator.internal.util.stereotypes.Immutable;

An aggregated view of the cascading validation metadata for containers. Note that it also includes the cascading validation metadata defined on the root element via the AnnotatedObject pseudo type parameter.
Author:Guillaume Smet
/** * An aggregated view of the cascading validation metadata for containers. Note that it also includes the cascading * validation metadata defined on the root element via the {@link AnnotatedObject} pseudo type parameter. * * @author Guillaume Smet */
public class ContainerCascadingMetaData implements CascadingMetaData { private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );
The enclosing type that defines this type parameter.
/** * The enclosing type that defines this type parameter. */
private final Type enclosingType;
The type parameter.
/** * The type parameter. */
private final TypeVariable<?> typeParameter;
The declared container class: it is the one used in the node of the property path.
/** * The declared container class: it is the one used in the node of the property path. */
private final Class<?> declaredContainerClass;
The declared type parameter: it is the one used in the node of the property path.
/** * The declared type parameter: it is the one used in the node of the property path. */
private final TypeVariable<?> declaredTypeParameter;
Index of the declared type parameter: it is the one used in the node of the property path. It is cached here for performance reasons.
/** * Index of the declared type parameter: it is the one used in the node of the property path. * It is cached here for performance reasons. */
private final Integer declaredTypeParameterIndex;
Possibly the cascading type parameters corresponding to this type parameter if it is a parameterized type.
/** * Possibly the cascading type parameters corresponding to this type parameter if it is a parameterized type. */
@Immutable private final List<ContainerCascadingMetaData> containerElementTypesCascadingMetaData;
If this type parameter is marked for cascading.
/** * If this type parameter is marked for cascading. */
private final boolean cascading;
The group conversions defined for this type parameter.
/** * The group conversions defined for this type parameter. */
private GroupConversionHelper groupConversionHelper;
Whether any container element (it can be nested) is marked for cascaded validation.
/** * Whether any container element (it can be nested) is marked for cascaded validation. */
private final boolean hasContainerElementsMarkedForCascading;
The set of value extractors which are type compliant and container element compliant with the element where the cascaded validation was declared. The final value extractor is chosen among these ones, based on the runtime type.
/** * The set of value extractors which are type compliant and container element compliant with the element where * the cascaded validation was declared. The final value extractor is chosen among these ones, based on the * runtime type. */
private final Set<ValueExtractorDescriptor> valueExtractorCandidates; public static ContainerCascadingMetaData of(ValueExtractorManager valueExtractorManager, CascadingMetaDataBuilder cascadingMetaDataBuilder, Object context) { return new ContainerCascadingMetaData( valueExtractorManager, cascadingMetaDataBuilder ); } private ContainerCascadingMetaData(ValueExtractorManager valueExtractorManager, CascadingMetaDataBuilder cascadingMetaDataBuilder) { this( valueExtractorManager, cascadingMetaDataBuilder.getEnclosingType(), cascadingMetaDataBuilder.getTypeParameter(), cascadingMetaDataBuilder.getDeclaredContainerClass(), cascadingMetaDataBuilder.getDeclaredTypeParameter(), cascadingMetaDataBuilder.getContainerElementTypesCascadingMetaData().entrySet().stream() .map( entry -> new ContainerCascadingMetaData( valueExtractorManager, entry.getValue() ) ) .collect( Collectors.collectingAndThen( Collectors.toList(), CollectionHelper::toImmutableList ) ), cascadingMetaDataBuilder.isCascading(), GroupConversionHelper.of( cascadingMetaDataBuilder.getGroupConversions() ), cascadingMetaDataBuilder.isMarkedForCascadingOnAnnotatedObjectOrContainerElements() ); } private ContainerCascadingMetaData(ValueExtractorManager valueExtractorManager, Type enclosingType, TypeVariable<?> typeParameter, Class<?> declaredContainerClass, TypeVariable<?> declaredTypeParameter, List<ContainerCascadingMetaData> containerElementTypesCascadingMetaData, boolean cascading, GroupConversionHelper groupConversionHelper, boolean markedForCascadingOnContainerElements) { this.enclosingType = enclosingType; this.typeParameter = typeParameter; this.declaredContainerClass = declaredContainerClass; this.declaredTypeParameter = declaredTypeParameter; this.declaredTypeParameterIndex = TypeVariables.getTypeParameterIndex( declaredTypeParameter ); this.containerElementTypesCascadingMetaData = containerElementTypesCascadingMetaData; this.cascading = cascading; this.groupConversionHelper = groupConversionHelper; this.hasContainerElementsMarkedForCascading = markedForCascadingOnContainerElements; if ( TypeVariables.isAnnotatedObject( this.typeParameter ) || !markedForCascadingOnContainerElements ) { this.valueExtractorCandidates = Collections.emptySet(); } else { this.valueExtractorCandidates = CollectionHelper.toImmutableSet( valueExtractorManager.getResolver().getValueExtractorCandidatesForCascadedValidation( this.enclosingType, this.typeParameter ) ); if ( this.valueExtractorCandidates.size() == 0 ) { throw LOG.getNoValueExtractorFoundForTypeException( this.declaredContainerClass, this.declaredTypeParameter ); } } } ContainerCascadingMetaData(Type enclosingType, List<ContainerCascadingMetaData> containerElementTypesCascadingMetaData, GroupConversionHelper groupConversionHelper, Set<ValueExtractorDescriptor> valueExtractorCandidates) { this.enclosingType = enclosingType; this.typeParameter = AnnotatedObject.INSTANCE; this.declaredContainerClass = null; this.declaredTypeParameter = null; this.declaredTypeParameterIndex = null; this.containerElementTypesCascadingMetaData = containerElementTypesCascadingMetaData; this.cascading = true; this.groupConversionHelper = groupConversionHelper; this.hasContainerElementsMarkedForCascading = true; this.valueExtractorCandidates = valueExtractorCandidates; } ContainerCascadingMetaData(Type enclosingType, TypeVariable<?> typeParameter, Class<?> declaredContainerClass, TypeVariable<?> declaredTypeParameter, GroupConversionHelper groupConversionHelper) { this.enclosingType = enclosingType; this.typeParameter = typeParameter; this.declaredContainerClass = declaredContainerClass; this.declaredTypeParameter = declaredTypeParameter; this.declaredTypeParameterIndex = TypeVariables.getTypeParameterIndex( declaredTypeParameter ); this.containerElementTypesCascadingMetaData = Collections.emptyList(); this.cascading = true; this.groupConversionHelper = groupConversionHelper; this.hasContainerElementsMarkedForCascading = false; this.valueExtractorCandidates = Collections.emptySet(); } @Override public boolean isContainer() { return true; } @Override public TypeVariable<?> getTypeParameter() { return typeParameter; } public Type getEnclosingType() { return enclosingType; } public Class<?> getDeclaredContainerClass() { return declaredContainerClass; } public TypeVariable<?> getDeclaredTypeParameter() { return declaredTypeParameter; } public Integer getDeclaredTypeParameterIndex() { return declaredTypeParameterIndex; } @Override public boolean isCascading() { return cascading; } public boolean hasContainerElementsMarkedForCascading() { return hasContainerElementsMarkedForCascading; } @Override public boolean isMarkedForCascadingOnAnnotatedObjectOrContainerElements() { return cascading || hasContainerElementsMarkedForCascading; } public List<ContainerCascadingMetaData> getContainerElementTypesCascadingMetaData() { return containerElementTypesCascadingMetaData; } @Override public Class<?> convertGroup(Class<?> originalGroup) { return groupConversionHelper.convertGroup( originalGroup ); } @Override public Set<GroupConversionDescriptor> getGroupConversionDescriptors() { return groupConversionHelper.asDescriptors(); } @Override @SuppressWarnings("unchecked") public <T extends CascadingMetaData> T as(Class<T> clazz) { if ( clazz.isAssignableFrom( getClass() ) ) { return (T) this; } throw LOG.getUnableToCastException( this, clazz ); } @Override public CascadingMetaData addRuntimeContainerSupport(ValueExtractorManager valueExtractorManager, Class<?> valueClass) { return this; } public Set<ValueExtractorDescriptor> getValueExtractorCandidates() { return valueExtractorCandidates; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append( getClass().getSimpleName() ); sb.append( " [" ); sb.append( "enclosingType=" ).append( StringHelper.toShortString( enclosingType ) ).append( ", " ); sb.append( "typeParameter=" ).append( typeParameter ).append( ", " ); sb.append( "cascading=" ).append( cascading ).append( ", " ); sb.append( "groupConversions=" ).append( groupConversionHelper ).append( ", " ); sb.append( "containerElementTypesCascadingMetaData=" ).append( containerElementTypesCascadingMetaData ); sb.append( "]" ); return sb.toString(); } }