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

org.hibernate.validator.internal.cfg.context.TypeConstraintMappingContextImpl 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.cfg.context;

import static org.hibernate.validator.internal.util.CollectionHelper.newHashSet;
import static org.hibernate.validator.internal.util.logging.Messages.MESSAGES;

import java.lang.annotation.ElementType;
import java.lang.invoke.MethodHandles;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import org.hibernate.validator.cfg.ConstraintDef;
import org.hibernate.validator.cfg.context.ConstructorConstraintMappingContext;
import org.hibernate.validator.cfg.context.MethodConstraintMappingContext;
import org.hibernate.validator.cfg.context.PropertyConstraintMappingContext;
import org.hibernate.validator.cfg.context.TypeConstraintMappingContext;
import org.hibernate.validator.internal.engine.ConstraintCreationContext;
import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl.ConstraintType;
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.ConstrainedType;
import org.hibernate.validator.internal.properties.Constrainable;
import org.hibernate.validator.internal.properties.javabean.JavaBeanConstructor;
import org.hibernate.validator.internal.properties.javabean.JavaBeanField;
import org.hibernate.validator.internal.properties.javabean.JavaBeanGetter;
import org.hibernate.validator.internal.properties.javabean.JavaBeanHelper;
import org.hibernate.validator.internal.properties.javabean.JavaBeanMethod;
import org.hibernate.validator.internal.util.Contracts;
import org.hibernate.validator.internal.util.ExecutableHelper;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;
import org.hibernate.validator.internal.util.privilegedactions.NewInstance;
import org.hibernate.validator.spi.group.DefaultGroupSequenceProvider;

/**
 * Constraint mapping creational context which allows to configure the class-level constraints for one bean.
 *
 * @param  The type represented by this creational context.
 *
 * @author Hardy Ferentschik
 * @author Gunnar Morling
 * @author Kevin Pollet <[email protected]> (C) 2011 SERLI
 * @author Marko Bekhta
 */
public final class TypeConstraintMappingContextImpl extends ConstraintMappingContextImplBase
		implements TypeConstraintMappingContext {

	private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );

	private final JavaBeanHelper javaBeanHelper;

	private final Class beanClass;

	private final Set executableContexts = newHashSet();
	private final Set> propertyContexts = newHashSet();
	private final Set configuredMembers = newHashSet();

	private List> defaultGroupSequence;
	private Class> defaultGroupSequenceProviderClass;

	TypeConstraintMappingContextImpl(JavaBeanHelper javaBeanHelper, DefaultConstraintMapping mapping, Class beanClass) {
		super( mapping );
		this.javaBeanHelper = javaBeanHelper;
		this.beanClass = beanClass;
		mapping.getAnnotationProcessingOptions().ignoreAnnotationConstraintForClass( beanClass, Boolean.FALSE );
	}

	@Override
	public TypeConstraintMappingContext constraint(ConstraintDef definition) {
		addConstraint( ConfiguredConstraint.forType( definition, beanClass ) );
		return this;
	}

	@Override
	@Deprecated
	public TypeConstraintMappingContext ignoreAnnotations() {
		return ignoreAnnotations( true );
	}

	@Override
	public TypeConstraintMappingContext ignoreAnnotations(boolean ignoreAnnotations) {
		mapping.getAnnotationProcessingOptions().ignoreClassLevelConstraintAnnotations( beanClass, ignoreAnnotations );
		return this;
	}

	@Override
	public TypeConstraintMappingContext ignoreAllAnnotations() {
		mapping.getAnnotationProcessingOptions().ignoreAnnotationConstraintForClass( beanClass, Boolean.TRUE );
		return this;
	}

	@Override
	public TypeConstraintMappingContext defaultGroupSequence(Class... defaultGroupSequence) {
		this.defaultGroupSequence = Arrays.asList( defaultGroupSequence );
		return this;
	}

	@Override
	public TypeConstraintMappingContext defaultGroupSequenceProviderClass(Class> defaultGroupSequenceProviderClass) {
		this.defaultGroupSequenceProviderClass = defaultGroupSequenceProviderClass;
		return this;
	}

	@Override
	@Deprecated
	public PropertyConstraintMappingContext property(String property, ElementType elementType) {
		Contracts.assertNotNull( elementType, "The element type must not be null." );

		if ( !( ElementType.FIELD.equals( elementType ) || ElementType.METHOD.equals( elementType ) ) ) {
			throw LOG.getElementTypeHasToBeFieldOrMethodException();
		}

		if ( ElementType.FIELD == elementType ) {
			return field( property );
		}
		else {
			return getter( property );
		}
	}

	@Override
	public PropertyConstraintMappingContext field(String property) {
		Contracts.assertNotEmpty( property, MESSAGES.propertyNameMustNotBeEmpty() );

		Optional foundField = javaBeanHelper.findDeclaredField( beanClass, property );

		if ( !foundField.isPresent() ) {
			throw LOG.getUnableToFindPropertyWithAccessException( beanClass, property, ElementType.FIELD );
		}

		JavaBeanField javaBeanField = foundField.get();

		if ( configuredMembers.contains( javaBeanField ) ) {
			throw LOG.getPropertyHasAlreadyBeConfiguredViaProgrammaticApiException( beanClass, property );
		}

		FieldConstraintMappingContextImpl context = new FieldConstraintMappingContextImpl( this, javaBeanField );
		configuredMembers.add( javaBeanField );
		propertyContexts.add( context );
		return context;
	}

	@Override
	public PropertyConstraintMappingContext getter(String property) {
		Contracts.assertNotEmpty( property, MESSAGES.propertyNameMustNotBeEmpty() );

		Optional foundGetter = javaBeanHelper.findDeclaredGetter( beanClass, property );

		if ( !foundGetter.isPresent() ) {
			throw LOG.getUnableToFindPropertyWithAccessException( beanClass, property, ElementType.METHOD );
		}

		JavaBeanGetter javaBeanGetter = foundGetter.get();

		if ( configuredMembers.contains( javaBeanGetter ) ) {
			throw LOG.getPropertyHasAlreadyBeConfiguredViaProgrammaticApiException( beanClass, property );
		}

		GetterConstraintMappingContextImpl context = new GetterConstraintMappingContextImpl( this, javaBeanGetter );
		configuredMembers.add( javaBeanGetter );
		propertyContexts.add( context );
		return context;
	}

	@Override
	public MethodConstraintMappingContext method(String name, Class... parameterTypes) {
		Contracts.assertNotNull( name, MESSAGES.methodNameMustNotBeNull() );

		Optional foundMethod = javaBeanHelper.findDeclaredMethod( beanClass, name, parameterTypes );

		if ( !foundMethod.isPresent() ) {
			throw LOG.getBeanDoesNotContainMethodException( beanClass, name, parameterTypes );
		}

		JavaBeanMethod javaBeanMethod = foundMethod.get();

		if ( configuredMembers.contains( javaBeanMethod ) ) {
			throw LOG.getMethodHasAlreadyBeenConfiguredViaProgrammaticApiException(
					beanClass,
					ExecutableHelper.getExecutableAsString( name, parameterTypes )
			);
		}

		MethodConstraintMappingContextImpl context = new MethodConstraintMappingContextImpl( this, javaBeanMethod );
		configuredMembers.add( javaBeanMethod );
		executableContexts.add( context );

		return context;
	}

	@Override
	public ConstructorConstraintMappingContext constructor(Class... parameterTypes) {
		Optional foundConstructor = javaBeanHelper.findDeclaredConstructor( beanClass, parameterTypes );

		if ( !foundConstructor.isPresent() ) {
			throw LOG.getBeanDoesNotContainConstructorException(
					beanClass,
					parameterTypes
			);
		}

		JavaBeanConstructor javaBeanConstructor = foundConstructor.get();

		if ( configuredMembers.contains( javaBeanConstructor ) ) {
			throw LOG.getConstructorHasAlreadyBeConfiguredViaProgrammaticApiException(
					beanClass,
					ExecutableHelper.getExecutableAsString( beanClass.getSimpleName(), parameterTypes )
			);
		}

		ConstructorConstraintMappingContextImpl context = new ConstructorConstraintMappingContextImpl(
				this,
				javaBeanConstructor
		);
		configuredMembers.add( javaBeanConstructor );
		executableContexts.add( context );

		return context;
	}

	BeanConfiguration build(ConstraintCreationContext constraintCreationContext) {
		return new BeanConfiguration<>(
				ConfigurationSource.API,
				beanClass,
				buildConstraintElements( constraintCreationContext ),
				defaultGroupSequence,
				getDefaultGroupSequenceProvider()
		);
	}

	private Set buildConstraintElements(ConstraintCreationContext constraintCreationContext) {
		Set elements = newHashSet();

		//class-level configuration
		elements.add(
				new ConstrainedType(
						ConfigurationSource.API,
						beanClass,
						getConstraints( constraintCreationContext )
				)
		);

		//constructors/methods
		for ( ExecutableConstraintMappingContextImpl executableContext : executableContexts ) {
			elements.add( executableContext.build( constraintCreationContext ) );
		}

		//properties
		for ( AbstractPropertyConstraintMappingContextImpl propertyContext : propertyContexts ) {
			elements.add( propertyContext.build( constraintCreationContext ) );
		}

		return elements;
	}

	private DefaultGroupSequenceProvider getDefaultGroupSequenceProvider() {
		return defaultGroupSequenceProviderClass != null ? run(
				NewInstance.action(
						defaultGroupSequenceProviderClass,
						"default group sequence provider"
				)
		) : null;
	}

	Class getBeanClass() {
		return beanClass;
	}

	@Override
	protected ConstraintType getConstraintType() {
		return ConstraintType.GENERIC;
	}

	/**
	 * Runs the given privileged action, using a privileged block if required.
	 * 

* NOTE: This must never be changed into a publicly available method to avoid execution of arbitrary * privileged actions within HV's protection domain. */ private T run(PrivilegedAction action) { return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy