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

org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataBuilder 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.util.List;
import java.util.Set;

import org.hibernate.validator.internal.engine.ConstraintCreationContext;
import org.hibernate.validator.internal.engine.MethodValidationConfiguration;
import org.hibernate.validator.internal.engine.groups.ValidationOrderGenerator;
import org.hibernate.validator.internal.metadata.raw.BeanConfiguration;
import org.hibernate.validator.internal.metadata.raw.ConfigurationSource;
import org.hibernate.validator.internal.metadata.raw.ConstrainedElement;
import org.hibernate.validator.internal.metadata.raw.ConstrainedExecutable;
import org.hibernate.validator.internal.metadata.raw.ConstrainedField;
import org.hibernate.validator.internal.metadata.raw.ConstrainedType;
import org.hibernate.validator.internal.properties.Callable;
import org.hibernate.validator.internal.util.ExecutableHelper;
import org.hibernate.validator.internal.util.ExecutableParameterNameProvider;
import org.hibernate.validator.internal.util.StringHelper;
import org.hibernate.validator.spi.group.DefaultGroupSequenceProvider;

/**
 * @author Hardy Ferentschik
 * @author Gunnar Morling
 * @author Kevin Pollet <[email protected]> (C) 2011 SERLI
 * @author Chris Beckey <[email protected]>
 * @author Guillaume Smet
 * @author Marko Bekhta
 */
public class BeanMetaDataBuilder {

	private final ConstraintCreationContext constraintCreationContext;
	private final ValidationOrderGenerator validationOrderGenerator;
	private final Class beanClass;
	private final Set builders = newHashSet();
	private final ExecutableHelper executableHelper;
	private final ExecutableParameterNameProvider parameterNameProvider;
	private final MethodValidationConfiguration methodValidationConfiguration;

	private ConfigurationSource sequenceSource;
	private ConfigurationSource providerSource;
	private List> defaultGroupSequence;
	private DefaultGroupSequenceProvider defaultGroupSequenceProvider;


	private BeanMetaDataBuilder(
			ConstraintCreationContext constraintCreationContext,
			ExecutableHelper executableHelper,
			ExecutableParameterNameProvider parameterNameProvider,
			ValidationOrderGenerator validationOrderGenerator,
			Class beanClass,
			MethodValidationConfiguration methodValidationConfiguration) {
		this.beanClass = beanClass;
		this.constraintCreationContext = constraintCreationContext;
		this.validationOrderGenerator = validationOrderGenerator;
		this.executableHelper = executableHelper;
		this.parameterNameProvider = parameterNameProvider;
		this.methodValidationConfiguration = methodValidationConfiguration;
	}

	public static  BeanMetaDataBuilder getInstance(
			ConstraintCreationContext constraintCreationContext,
			ExecutableHelper executableHelper,
			ExecutableParameterNameProvider parameterNameProvider,
			ValidationOrderGenerator validationOrderGenerator,
			Class beanClass,
			MethodValidationConfiguration methodValidationConfiguration) {
		return new BeanMetaDataBuilder<>(
				constraintCreationContext,
				executableHelper,
				parameterNameProvider,
				validationOrderGenerator,
				beanClass,
				methodValidationConfiguration );
	}

	public void add(BeanConfiguration configuration) {
		if ( configuration.getBeanClass().equals( beanClass ) ) {
			if ( configuration.getDefaultGroupSequence() != null
					&& ( sequenceSource == null || configuration.getSource()
					.getPriority() >= sequenceSource.getPriority() ) ) {

				sequenceSource = configuration.getSource();
				defaultGroupSequence = configuration.getDefaultGroupSequence();
			}

			if ( configuration.getDefaultGroupSequenceProvider() != null
					&& ( providerSource == null || configuration.getSource()
					.getPriority() >= providerSource.getPriority() ) ) {

				providerSource = configuration.getSource();
				defaultGroupSequenceProvider = configuration.getDefaultGroupSequenceProvider();
			}
		}

		for ( ConstrainedElement constrainedElement : configuration.getConstrainedElements() ) {
			addMetaDataToBuilder( constrainedElement, builders );
		}
	}

	private void addMetaDataToBuilder(ConstrainedElement constrainableElement, Set builders) {
		for ( BuilderDelegate builder : builders ) {
			boolean foundBuilder = builder.add( constrainableElement );

			if ( foundBuilder ) {
				return;
			}
		}

		builders.add(
				new BuilderDelegate(
						beanClass,
						constrainableElement,
						constraintCreationContext,
						executableHelper,
						parameterNameProvider,
						methodValidationConfiguration
				)
		);
	}

	public BeanMetaDataImpl build() {
		Set aggregatedElements = newHashSet();

		for ( BuilderDelegate builder : builders ) {
			aggregatedElements.addAll( builder.build() );
		}

		return new BeanMetaDataImpl<>(
				beanClass,
				defaultGroupSequence,
				defaultGroupSequenceProvider,
				aggregatedElements,
				validationOrderGenerator
		);
	}

	private static class BuilderDelegate {
		private final Class beanClass;
		private final ConstrainedElement constrainedElement;
		private final ConstraintCreationContext constraintCreationContext;
		private final ExecutableHelper executableHelper;
		private final ExecutableParameterNameProvider parameterNameProvider;
		private MetaDataBuilder metaDataBuilder;
		private ExecutableMetaData.Builder methodBuilder;
		private final MethodValidationConfiguration methodValidationConfiguration;
		private final int hashCode;

		public BuilderDelegate(
				Class beanClass,
				ConstrainedElement constrainedElement,
				ConstraintCreationContext constraintCreationContext,
				ExecutableHelper executableHelper,
				ExecutableParameterNameProvider parameterNameProvider,
				MethodValidationConfiguration methodValidationConfiguration
		) {
			this.beanClass = beanClass;
			this.constrainedElement = constrainedElement;
			this.constraintCreationContext = constraintCreationContext;
			this.executableHelper = executableHelper;
			this.parameterNameProvider = parameterNameProvider;
			this.methodValidationConfiguration = methodValidationConfiguration;

			switch ( constrainedElement.getKind() ) {
				case FIELD:
					ConstrainedField constrainedField = (ConstrainedField) constrainedElement;
					metaDataBuilder = new PropertyMetaData.Builder(
							beanClass,
							constrainedField,
							constraintCreationContext
					);
					break;
				case CONSTRUCTOR:
				case METHOD:
				case GETTER:
					ConstrainedExecutable constrainedExecutable = (ConstrainedExecutable) constrainedElement;
					Callable callable = constrainedExecutable.getCallable();

					// HV-890 Not adding meta-data for private super-type methods to the method meta-data of this bean;
					// It is not needed and it may conflict with sub-type methods of the same signature
					if ( !callable.isPrivate() || beanClass == callable.getDeclaringClass() ) {
						methodBuilder = new ExecutableMetaData.Builder(
								beanClass,
								constrainedExecutable,
								constraintCreationContext,
								executableHelper,
								parameterNameProvider,
								methodValidationConfiguration
						);
					}

					if ( constrainedElement.getKind() == ConstrainedElement.ConstrainedElementKind.GETTER ) {
						metaDataBuilder = new PropertyMetaData.Builder(
								beanClass,
								constrainedExecutable,
								constraintCreationContext
						);
					}
					break;
				case TYPE:
					ConstrainedType constrainedType = (ConstrainedType) constrainedElement;
					metaDataBuilder = new ClassMetaData.Builder(
							beanClass,
							constrainedType,
							constraintCreationContext
					);
					break;
				default:
					throw new IllegalStateException(
							StringHelper.format( "Constrained element kind '%1$s' not supported here.", constrainedElement.getKind() ) );
			}

			this.hashCode = buildHashCode();
		}

		public boolean add(ConstrainedElement constrainedElement) {
			boolean added = false;

			if ( methodBuilder != null && methodBuilder.accepts( constrainedElement ) ) {
				methodBuilder.add( constrainedElement );
				added = true;
			}

			if ( metaDataBuilder != null && metaDataBuilder.accepts( constrainedElement ) ) {
				metaDataBuilder.add( constrainedElement );

				if ( !added && constrainedElement.getKind().isMethod() && methodBuilder == null ) {
					ConstrainedExecutable constrainedMethod = (ConstrainedExecutable) constrainedElement;
					methodBuilder = new ExecutableMetaData.Builder(
							beanClass,
							constrainedMethod,
							constraintCreationContext,
							executableHelper,
							parameterNameProvider,
							methodValidationConfiguration
					);
				}

				added = true;
			}

			return added;
		}

		public Set build() {
			Set metaDataSet = newHashSet();

			if ( metaDataBuilder != null ) {
				metaDataSet.add( metaDataBuilder.build() );
			}

			if ( methodBuilder != null ) {
				metaDataSet.add( methodBuilder.build() );
			}

			return metaDataSet;
		}

		@Override
		public int hashCode() {
			return hashCode;
		}

		private int buildHashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + beanClass.hashCode();
			result = prime * result + constrainedElement.hashCode();
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if ( this == obj ) {
				return true;
			}
			if ( !super.equals( obj ) ) {
				return false;
			}
			if ( getClass() != obj.getClass() ) {
				return false;
			}
			BuilderDelegate other = (BuilderDelegate) obj;
			if ( !beanClass.equals( other.beanClass ) ) {
				return false;
			}
			if ( !constrainedElement.equals( other.constrainedElement ) ) {
				return false;
			}
			return true;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy