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

org.hibernate.validator.internal.metadata.aggregated.AbstractConstraintMetaData Maven / Gradle / Ivy

There is a newer version: 8.0.1.Final
Show newest version
/*
 * Hibernate Validator, declare and validate application constraints
 *
 * License: Apache License, Version 2.0
 * See the license.txt file in the root directory or .
 */
package org.hibernate.validator.internal.metadata.aggregated;

import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet;

import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.validation.metadata.ContainerElementTypeDescriptor;
import javax.validation.metadata.GroupConversionDescriptor;

import org.hibernate.validator.internal.metadata.core.MetaConstraint;
import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl;
import org.hibernate.validator.internal.metadata.descriptor.ContainerElementTypeDescriptorImpl;
import org.hibernate.validator.internal.metadata.location.ConstraintLocation;
import org.hibernate.validator.internal.metadata.location.TypeArgumentConstraintLocation;
import org.hibernate.validator.internal.util.CollectionHelper;
import org.hibernate.validator.internal.util.TypeVariables;
import org.hibernate.validator.internal.util.stereotypes.Immutable;

/**
 * Base implementation for {@link ConstraintMetaData} with attributes common
 * to all type of meta data.
 *
 * @author Gunnar Morling
 * @author Hardy Ferentschik
 */
public abstract class AbstractConstraintMetaData implements ConstraintMetaData {

	private final String name;
	private final Type type;
	@Immutable
	private final Set> directConstraints;
	@Immutable
	private final Set> containerElementsConstraints;
	@Immutable
	private final Set>  allConstraints;
	private final boolean isCascading;
	private final boolean isConstrained;

	public AbstractConstraintMetaData(String name,
									  Type type,
									  Set> directConstraints,
									  Set> containerElementsConstraints,
									  boolean isCascading,
									  boolean isConstrained) {
		this.name = name;
		this.type = type;
		this.directConstraints = CollectionHelper.toImmutableSet( directConstraints );
		this.containerElementsConstraints = CollectionHelper.toImmutableSet( containerElementsConstraints );
		this.allConstraints = Stream.concat( directConstraints.stream(), containerElementsConstraints.stream() )
				.collect( Collectors.collectingAndThen( Collectors.toSet(), CollectionHelper::toImmutableSet ) );
		this.isCascading = isCascading;
		this.isConstrained = isConstrained;
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public Type getType() {
		return type;
	}

	@Override
	public Iterator> iterator() {
		return allConstraints.iterator();
	}

	public Set> getAllConstraints() {
		return allConstraints;
	}

	public Set> getDirectConstraints() {
		return directConstraints;
	}

	public Set> getContainerElementsConstraints() {
		return containerElementsConstraints;
	}

	@Override
	public final boolean isCascading() {
		return isCascading;
	}

	@Override
	public boolean isConstrained() {
		return isConstrained;
	}

	@Override
	public String toString() {
		return "AbstractConstraintMetaData [name=" + name + ", type=" + type
				+ ", directConstraints=" + directConstraints
				+ ", containerElementsConstraints=" + containerElementsConstraints
				+ ", isCascading=" + isCascading
				+ ", isConstrained=" + isConstrained + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ( ( name == null ) ? 0 : name.hashCode() );
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if ( this == obj ) {
			return true;
		}
		if ( obj == null ) {
			return false;
		}
		if ( getClass() != obj.getClass() ) {
			return false;
		}
		AbstractConstraintMetaData other = (AbstractConstraintMetaData) obj;
		if ( name == null ) {
			if ( other.name != null ) {
				return false;
			}
		}
		else if ( !name.equals( other.name ) ) {
			return false;
		}
		return true;
	}

	protected Set> asDescriptors(Set> constraints) {
		Set> theValue = newHashSet();

		for ( MetaConstraint oneConstraint : constraints ) {
			theValue.add( oneConstraint.getDescriptor() );
		}

		return theValue;
	}

	protected Set asContainerElementTypeDescriptors(
			Set> containerElementsConstraints, CascadingMetaData cascadingMetaData,
			boolean defaultGroupSequenceRedefined, List> defaultGroupSequence) {

		return asContainerElementTypeDescriptors( type,
				ContainerElementMetaDataTree.of( cascadingMetaData, containerElementsConstraints ),
				defaultGroupSequenceRedefined, defaultGroupSequence );
	}

	private Set asContainerElementTypeDescriptors(Type type, ContainerElementMetaDataTree containerElementMetaDataTree,
			boolean defaultGroupSequenceRedefined, List> defaultGroupSequence) {
		Set containerElementTypeDescriptors = new HashSet<>();

		for ( Entry, ContainerElementMetaDataTree> entry : containerElementMetaDataTree.nodes.entrySet() ) {
			TypeVariable childTypeParameter = entry.getKey();
			ContainerElementMetaDataTree childContainerElementMetaDataTree = entry.getValue();

			Set childrenDescriptors =
					asContainerElementTypeDescriptors( childContainerElementMetaDataTree.elementType, childContainerElementMetaDataTree,
					defaultGroupSequenceRedefined, defaultGroupSequence );

			containerElementTypeDescriptors.add( new ContainerElementTypeDescriptorImpl(
					childContainerElementMetaDataTree.elementType,
					childContainerElementMetaDataTree.containerClass, TypeVariables.getTypeParameterIndex( childTypeParameter ),
					asDescriptors( childContainerElementMetaDataTree.constraints ),
					childrenDescriptors,
					childContainerElementMetaDataTree.cascading,
					defaultGroupSequenceRedefined, defaultGroupSequence,
					childContainerElementMetaDataTree.groupConversionDescriptors ) );
		}

		return containerElementTypeDescriptors;
	}

	/**
	 * This data structure is used to join the cascading metadata information with the constraint violations. It is a
	 * temporary data structure and it should be kept that way.
	 * 

* We might consider in the future having a common tree structure for the cascading metadata and the constraint * violations that would be built earlier and shared. This class shouldn't be taken as a model as this data * structure should be made immutable. */ private static class ContainerElementMetaDataTree { private final Map, ContainerElementMetaDataTree> nodes = new HashMap<>(); private Type elementType = null; private Class containerClass; private final Set> constraints = new HashSet<>(); private boolean cascading = false; private Set groupConversionDescriptors = new HashSet<>(); private static ContainerElementMetaDataTree of(CascadingMetaData cascadingMetaData, Set> containerElementsConstraints) { ContainerElementMetaDataTree containerElementMetaConstraintTree = new ContainerElementMetaDataTree(); for ( MetaConstraint constraint : containerElementsConstraints ) { ConstraintLocation currentLocation = constraint.getLocation(); List> constraintPath = new ArrayList<>(); while ( currentLocation instanceof TypeArgumentConstraintLocation ) { TypeArgumentConstraintLocation typeArgumentConstraintLocation = ( (TypeArgumentConstraintLocation) currentLocation ); constraintPath.add( typeArgumentConstraintLocation.getTypeParameter() ); currentLocation = typeArgumentConstraintLocation.getDelegate(); } Collections.reverse( constraintPath ); containerElementMetaConstraintTree.addConstraint( constraintPath, constraint ); } if ( cascadingMetaData != null && cascadingMetaData.isContainer() && cascadingMetaData.isMarkedForCascadingOnAnnotatedObjectOrContainerElements() ) { containerElementMetaConstraintTree.addCascadingMetaData( new ArrayList<>(), cascadingMetaData.as( ContainerCascadingMetaData.class ) ); } return containerElementMetaConstraintTree; } private void addConstraint(List> path, MetaConstraint constraint) { ContainerElementMetaDataTree tree = this; for ( TypeVariable typeArgument : path ) { tree = tree.nodes.computeIfAbsent( typeArgument, ta -> new ContainerElementMetaDataTree() ); } TypeArgumentConstraintLocation constraintLocation = (TypeArgumentConstraintLocation) constraint.getLocation(); tree.elementType = constraintLocation.getTypeForValidatorResolution(); tree.containerClass = ( (TypeArgumentConstraintLocation) constraint.getLocation() ).getContainerClass(); tree.constraints.add( constraint ); } private void addCascadingMetaData(List> path, ContainerCascadingMetaData cascadingMetaData) { for ( ContainerCascadingMetaData nestedCascadingMetaData : cascadingMetaData.getContainerElementTypesCascadingMetaData() ) { List> nestedPath = new ArrayList<>( path ); nestedPath.add( nestedCascadingMetaData.getTypeParameter() ); ContainerElementMetaDataTree tree = this; for ( TypeVariable typeArgument : nestedPath ) { tree = tree.nodes.computeIfAbsent( typeArgument, ta -> new ContainerElementMetaDataTree() ); } tree.elementType = TypeVariables.getContainerElementType( nestedCascadingMetaData.getEnclosingType(), nestedCascadingMetaData.getTypeParameter() ); tree.containerClass = nestedCascadingMetaData.getDeclaredContainerClass(); tree.cascading = nestedCascadingMetaData.isCascading(); tree.groupConversionDescriptors = nestedCascadingMetaData.getGroupConversionDescriptors(); if ( nestedCascadingMetaData.isMarkedForCascadingOnAnnotatedObjectOrContainerElements() ) { addCascadingMetaData( nestedPath, nestedCascadingMetaData ); } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy