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

org.hibernate.validator.internal.properties.javabean.JavaBeanExecutable 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.properties.javabean;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.hibernate.validator.internal.properties.Callable;
import org.hibernate.validator.internal.util.CollectionHelper;
import org.hibernate.validator.internal.util.ExecutableHelper;
import org.hibernate.validator.internal.util.ExecutableParameterNameProvider;
import org.hibernate.validator.internal.util.ReflectionHelper;
import org.hibernate.validator.internal.util.TypeHelper;

/**
 * @author Marko Bekhta
 * @author Guillaume Smet
 */
public abstract class JavaBeanExecutable implements Callable, JavaBeanAnnotatedConstrainable {

	protected final T executable;
	private final Type typeForValidatorResolution;
	private final boolean hasReturnValue;
	private final Type type;
	private final List parameters;

	JavaBeanExecutable(T executable, boolean hasReturnValue) {
		this.executable = executable;
		this.type = ReflectionHelper.typeOf( executable );
		this.typeForValidatorResolution = ReflectionHelper.boxedType( type );
		this.hasReturnValue = hasReturnValue;
		this.parameters = getParameters( executable );
	}

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

	@Override
	public boolean hasParameters() {
		return !parameters.isEmpty();
	}

	@Override
	public String getName() {
		return executable.getName();
	}

	@Override
	public Class getDeclaringClass() {
		return executable.getDeclaringClass();
	}

	@Override
	public Type getTypeForValidatorResolution() {
		return typeForValidatorResolution;
	}

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

	@Override
	public String getParameterName(ExecutableParameterNameProvider parameterNameProvider, int parameterIndex) {
		return parameterNameProvider.getParameterNames( executable ).get( parameterIndex );
	}

	@Override
	public boolean isPrivate() {
		return Modifier.isPrivate( executable.getModifiers() );
	}

	@Override
	public String getSignature() {
		return ExecutableHelper.getSignature( executable );
	}

	@Override
	public Annotation[] getDeclaredAnnotations() {
		return executable.getDeclaredAnnotations();
	}

	@Override
	public boolean overrides(ExecutableHelper executableHelper, Callable superTypeMethod) {
		return executableHelper.overrides( ( (Method) this.executable ), ( (Method) ( (JavaBeanExecutable) superTypeMethod ).executable ) );
	}

	@Override
	public boolean isResolvedToSameMethodInHierarchy(ExecutableHelper executableHelper, Class mainSubType, Callable superTypeMethod) {
		return executableHelper.isResolvedToSameMethodInHierarchy( mainSubType, ( (Method) this.executable ), ( (Method) ( (JavaBeanExecutable) superTypeMethod ).executable ) );
	}

	@Override
	public Type getGenericType() {
		return ReflectionHelper.typeOf( executable );
	}

	@Override
	public AnnotatedType getAnnotatedType() {
		return executable.getAnnotatedReturnType();
	}

	@Override
	public  A getAnnotation(Class annotationClass) {
		return executable.getAnnotation( annotationClass );
	}

	public List getParameters() {
		return parameters;
	}

	@Override
	public Type getParameterGenericType(int index) {
		return parameters.get( index ).getGenericType();
	}

	@Override
	public int getParameterCount() {
		return parameters.size();
	}

	@Override
	public Class[] getParameterTypes() {
		return executable.getParameterTypes();
	}

	@Override
	public boolean equals(Object o) {
		if ( this == o ) {
			return true;
		}
		if ( o == null || this.getClass() != o.getClass() ) {
			return false;
		}

		JavaBeanExecutable that = (JavaBeanExecutable) o;

		if ( this.hasReturnValue != that.hasReturnValue ) {
			return false;
		}
		if ( !this.executable.equals( that.executable ) ) {
			return false;
		}
		if ( !this.typeForValidatorResolution.equals( that.typeForValidatorResolution ) ) {
			return false;
		}
		return this.type.equals( that.type );
	}

	@Override
	public int hashCode() {
		int result = this.executable.hashCode();
		result = 31 * result + this.typeForValidatorResolution.hashCode();
		result = 31 * result + ( this.hasReturnValue ? 1 : 0 );
		result = 31 * result + this.type.hashCode();
		return result;
	}

	@Override
	public String toString() {
		return ExecutableHelper.getExecutableAsString(
				getDeclaringClass().getSimpleName() + "#" + executable.getName(),
				executable.getParameterTypes()
		);
	}

	private static List getParameters(Executable executable) {
		if ( executable.getParameterCount() == 0 ) {
			return Collections.emptyList();
		}

		List parameters = new ArrayList<>( executable.getParameterCount() );

		Parameter[] parameterArray = executable.getParameters();
		Class[] parameterTypes = executable.getParameterTypes();
		// getGenericParameterTypes() does not include either the synthetic or the implicit parameters so we need to be
		// extra careful
		Type[] genericParameterTypes = executable.getGenericParameterTypes();

		if ( parameterTypes.length == genericParameterTypes.length ) {
			// this is the simple case where both arrays are consistent
			// we could do without it but at some point, the behavior of getGenericParameterTypes() might be changed in
			// Java and we'd better be ready.
			for ( int i = 0; i < parameterArray.length; i++ ) {
				parameters.add( new JavaBeanParameter( i, parameterArray[i], parameterTypes[i], getErasedTypeIfTypeVariable( genericParameterTypes[i] ) ) );
			}
		}
		else {
			// in this case, we have synthetic or implicit parameters
			int explicitlyDeclaredParameterIndex = 0;

			for ( int i = 0; i < parameterArray.length; i++ ) {
				if ( parameterArray[i].isSynthetic() || parameterArray[i].isImplicit() ) {
					// in this case, the parameter is not present in genericParameterTypes
					parameters.add( new JavaBeanParameter( i, parameterArray[i], parameterTypes[i], parameterTypes[i] ) );
				}
				else {
					parameters.add( new JavaBeanParameter( i, parameterArray[i], parameterTypes[i],
							getErasedTypeIfTypeVariable( genericParameterTypes[explicitlyDeclaredParameterIndex] ) ) );
					explicitlyDeclaredParameterIndex++;
				}
			}
		}

		return CollectionHelper.toImmutableList( parameters );
	}

	private static Type getErasedTypeIfTypeVariable(Type genericType) {
		if ( genericType instanceof TypeVariable ) {
			return TypeHelper.getErasedType( genericType );
		}

		return genericType;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy