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

org.hibernate.models.internal.jandex.JandexMethodDetails Maven / Gradle / Ivy

/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * SPDX-License-Identifier: Apache-2.0
 * Copyright: Red Hat Inc. and Hibernate Authors
 */
package org.hibernate.models.internal.jandex;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.hibernate.models.spi.MutableMemberDetails;
import org.hibernate.models.spi.ClassBasedTypeDetails;
import org.hibernate.models.spi.ClassDetails;
import org.hibernate.models.spi.ClassDetailsRegistry;
import org.hibernate.models.spi.MethodDetails;
import org.hibernate.models.spi.SourceModelBuildingContext;
import org.hibernate.models.spi.TypeDetails;
import org.hibernate.models.spi.TypeDetailsHelper;
import org.hibernate.models.spi.TypeVariableScope;

import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.MethodInfo;
import org.jboss.jandex.Type;

import static org.hibernate.models.spi.MethodDetails.MethodKind.GETTER;
import static org.hibernate.models.spi.MethodDetails.MethodKind.SETTER;

/**
 * @author Steve Ebersole
 */
public class JandexMethodDetails extends AbstractAnnotationTarget implements MethodDetails, MutableMemberDetails {
	private final MethodInfo methodInfo;
	private final MethodKind methodKind;
	private final TypeDetails type;
	private final ClassDetails declaringType;

	private final ClassDetails returnType;
	private final List argumentTypes;

	private final boolean isArray;
	private final boolean isPlural;

	public JandexMethodDetails(
			MethodInfo methodInfo,
			MethodKind methodKind,
			TypeDetails type,
			ClassDetails declaringType,
			SourceModelBuildingContext buildingContext) {
		super( buildingContext );
		this.methodInfo = methodInfo;
		this.methodKind = methodKind;
		this.type = type;
		this.declaringType = declaringType;

		final ClassDetailsRegistry classDetailsRegistry = buildingContext.getClassDetailsRegistry();
		this.returnType = classDetailsRegistry.resolveClassDetails( methodInfo.returnType().name().toString() );

		this.argumentTypes = new ArrayList<>( methodInfo.parametersCount() );
		for ( int i = 0; i < methodInfo.parametersCount(); i++ ) {
			argumentTypes.add( classDetailsRegistry.resolveClassDetails( methodInfo.parameterType( i ).name().toString() ) );
		}

		switch ( methodKind ) {
			case GETTER -> {
				this.isArray = methodInfo.returnType().kind() == Type.Kind.ARRAY;
				this.isPlural = isArray || type.isImplementor( Collection.class ) || type.isImplementor( Map.class );
			}
			case SETTER -> {
				assert methodInfo.parametersCount() == 1;
				this.isArray = methodInfo.parameterType( 0 ).kind() == Type.Kind.ARRAY;
				this.isPlural = isArray || type.isImplementor( Collection.class ) || type.isImplementor( Map.class );
			}
			default -> {
				this.isArray = false;
				this.isPlural = false;
			}
		}
	}

	@Override
	protected AnnotationTarget getJandexAnnotationTarget() {
		return methodInfo;
	}

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

	@Override
	public MethodKind getMethodKind() {
		return methodKind;
	}

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

	@Override
	public ClassDetails getDeclaringType() {
		return declaringType;
	}

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

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

	@Override
	public int getModifiers() {
		return methodInfo.flags();
	}

	private Method underlyingMethod;

	@Override
	public Method toJavaMember() {
		if ( underlyingMethod == null ) {
			underlyingMethod = resolveJavaMember();
		}
		return underlyingMethod;
	}

	@Override
	public TypeDetails resolveRelativeType(TypeVariableScope container) {
		if ( methodKind == GETTER || methodKind == SETTER ) {
			return type.determineRelativeType( container );
		}
		throw new IllegalStateException( "Method does not have a type - " + this );
	}

	@Override
	public ClassBasedTypeDetails resolveRelativeClassType(TypeVariableScope container) {
		if ( methodKind == GETTER || methodKind == SETTER ) {
			return TypeDetailsHelper.resolveRelativeClassType( type, container );
		}
		throw new IllegalStateException( "Method does not have a type - " + this );
	}

	private Method resolveJavaMember() {
		final Class declaringTypeClass = declaringType.toJavaClass();
		methods: for ( Method method : declaringTypeClass.getDeclaredMethods() ) {
			if ( !method.getName().equals( methodInfo.name() ) ) {
				continue;
			}

			if ( method.getParameterCount() != methodInfo.parametersCount() ) {
				continue;
			}

			for ( int i = 0; i < method.getParameterTypes().length; i++ ) {
				final Class methodParameterType = method.getParameterTypes()[i];
				final Type expectedType = methodInfo.parameterType( i );
				if ( !methodParameterType.getName().equals( expectedType.name().toString() ) ) {
					continue methods;
				}
			}

			// if we get here, we've found it
			return method;
		}

		throw new RuntimeException(
				String.format(
						"Jandex FieldInfo had no corresponding Field : %s.%s",
						declaringType.getName(),
						methodInfo.name()
				)
		);	}

	@Override
	public ClassDetails getReturnType() {
		return returnType;
	}

	@Override
	public List getArgumentTypes() {
		return argumentTypes;
	}

	@Override
	public String toString() {
		return String.format(
				Locale.ROOT,
				"JandexMethodDetails( [%s] %s )",
				methodKind.name(),
				methodInfo.toString()
		);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy