Package org.hibernate.validator.internal.metadata.provider

Source Code of org.hibernate.validator.internal.metadata.provider.TypeAnnotationAwareMetaDataProvider

/*
* 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.provider;

import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.AnnotatedParameterizedType;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import javax.validation.ParameterNameProvider;
import javax.validation.Valid;

import org.hibernate.validator.internal.metadata.core.AnnotationProcessingOptions;
import org.hibernate.validator.internal.metadata.core.ConstraintHelper;
import org.hibernate.validator.internal.metadata.core.MetaConstraint;
import org.hibernate.validator.internal.metadata.descriptor.ConstraintDescriptorImpl;
import org.hibernate.validator.internal.metadata.location.ConstraintLocation;
import org.hibernate.validator.internal.util.IgnoreJava6Requirement;
import org.hibernate.validator.internal.util.ReflectionHelper;
import org.hibernate.validator.internal.util.TypeHelper;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;

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

/**
* Extends {@code AnnotationMetaDataProvider} by discovering and registering constraints defined via Java 8 type
* annotations.
*
* @author Khalid Alqinyah
* @author Hardy Ferentschik
*/
@IgnoreJava6Requirement
public class TypeAnnotationAwareMetaDataProvider extends AnnotationMetaDataProvider {

  private static final Log log = LoggerFactory.make();

  public TypeAnnotationAwareMetaDataProvider(ConstraintHelper constraintHelper,
                         ParameterNameProvider parameterNameProvider,
                         AnnotationProcessingOptions annotationProcessingOptions) {
    super( constraintHelper, parameterNameProvider, annotationProcessingOptions );
  }

  @Override
  protected Set<MetaConstraint<?>> findTypeAnnotationConstraintsForMember(Member member) {
    AnnotatedType annotatedType = null;

    if ( member instanceof Field ) {
      annotatedType = ( (Field) member ).getAnnotatedType();
    }

    if ( member instanceof Method ) {
      annotatedType = ( (Method) member ).getAnnotatedReturnType();
    }

    return findTypeArgumentsConstraints(
        member,
        annotatedType,
        ( (AccessibleObject) member ).isAnnotationPresent( Valid.class )
    );
  }

  @Override
  protected Set<MetaConstraint<?>> findTypeAnnotationConstraintsForExecutableParameter(Member member, int i) {
    Parameter parameter = ( (Executable) member ).getParameters()[i];
    try {
      return findTypeArgumentsConstraints(
          member,
          parameter.getAnnotatedType(),
          parameter.isAnnotationPresent( Valid.class )
      );
    }
    catch ( ArrayIndexOutOfBoundsException ex ) {
      log.warn( MESSAGES.constraintOnConstructorOfNonStaticInnerClass(), ex );
      return Collections.emptySet();
    }
  }

  private Set<MetaConstraint<?>> findTypeArgumentsConstraints(Member member, AnnotatedType annotatedType, boolean isCascaded) {
    Optional<AnnotatedType> typeParameter = getTypeParameter( annotatedType );
    if ( !typeParameter.isPresent() ) {
      return Collections.emptySet();
    }

    List<ConstraintDescriptorImpl<?>> constraintDescriptors = findTypeUseConstraints( member, typeParameter.get() );
    if ( constraintDescriptors.isEmpty() ) {
      return Collections.emptySet();
    }

    // HV-925
    // We need to determine the validated type used for constraint validator resolution.
    // Iterables and maps need special treatment at this point, since the validated type is the type of the
    // specified type parameter. In the other cases the validated type is the parameterized type, eg Optional<String>.
    // In the latter case a value unwrapping has to occur
    Type validatedType = annotatedType.getType();
    if ( ReflectionHelper.isIterable( annotatedType.getType() ) || ReflectionHelper.isMap( annotatedType.getType() ) ) {
      if ( !isCascaded ) {
        throw log.getTypeAnnotationConstraintOnIterableRequiresUseOfValidAnnotationException(
            member.getDeclaringClass().getName(),
            member.getName()
        );
      }
      validatedType = typeParameter.get().getType();
    }

    return convertToTypeArgumentMetaConstraints(
        constraintDescriptors,
        member,
        validatedType
    );
  }

  /**
   * Finds type use annotation constraints defined on the type argument.
   */
  private List<ConstraintDescriptorImpl<?>> findTypeUseConstraints(Member member, AnnotatedType typeArgument) {
    List<ConstraintDescriptorImpl<?>> metaData = newArrayList();

    for ( Annotation annotation : typeArgument.getAnnotations() ) {
      metaData.addAll( findConstraintAnnotations( member, annotation, ElementType.TYPE_USE ) );
    }

    return metaData;
  }

  /**
   * Creates meta constraints for type arguments constraints.
   */
  private Set<MetaConstraint<?>> convertToTypeArgumentMetaConstraints(List<ConstraintDescriptorImpl<?>> constraintDescriptors, Member member, Type type) {
    Set<MetaConstraint<?>> constraints = newHashSet( constraintDescriptors.size() );
    for ( ConstraintDescriptorImpl<?> constraintDescription : constraintDescriptors ) {
      MetaConstraint<?> metaConstraint = createTypeArgumentMetaConstraint( member, constraintDescription, type );
      constraints.add( metaConstraint );
    }
    return constraints;
  }

  /**
   * Creates a {@code MetaConstraint} for a type argument constraint.
   */
  private <A extends Annotation> MetaConstraint<?> createTypeArgumentMetaConstraint(Member member, ConstraintDescriptorImpl<A> descriptor, Type type) {
    return new MetaConstraint<A>( descriptor, ConstraintLocation.forTypeArgument( member, type ) );
  }

  /**
   * Returns the type argument of a parameterized type. If the type is a {@code Map}, the method returns the value
   * type argument. If the type has more than one type argument and is not a Map, the method returns an empty {@code
   * Optional}.
   */
  private Optional<AnnotatedType> getTypeParameter(AnnotatedType annotatedType) {
    if ( annotatedType == null ) {
      return Optional.empty();
    }

    if ( !TypeHelper.isAssignable( AnnotatedParameterizedType.class, annotatedType.getClass() ) ) {
      return Optional.empty();
    }

    AnnotatedType[] annotatedArguments = ( (AnnotatedParameterizedType) annotatedType ).getAnnotatedActualTypeArguments();

    // One type argument, return it
    if ( annotatedArguments.length == 1 ) {
      return Optional.of( annotatedArguments[0] );
    }

    // More than one type argument
    if ( annotatedArguments.length > 1 ) {

      // If it is a Map, return the value type argument
      if ( ReflectionHelper.isMap( annotatedType.getType() ) ) {
        return Optional.of( annotatedArguments[1] );
      }

      // If it is not a Map, log a message and ignore
      log.parameterizedTypeWithMoreThanOneTypeArgumentIsNotSupported();
    }

    return Optional.empty();
  }
}
TOP

Related Classes of org.hibernate.validator.internal.metadata.provider.TypeAnnotationAwareMetaDataProvider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.