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

org.hibernate.boot.internal.AttributeConverterDescriptorNonAutoApplicableImpl Maven / Gradle / Ivy

The newest version!
/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or .
 */
package org.hibernate.boot.internal;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.persistence.AttributeConverter;

import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.spi.AttributeConverterDescriptor;
import org.hibernate.boot.spi.MetadataBuildingContext;

/**
 * Special-use AttributeConverterDescriptor implementation for cases where the converter will never
 * be used for auto-apply.
 *
 * @author Steve Ebersole
 */
public class AttributeConverterDescriptorNonAutoApplicableImpl implements AttributeConverterDescriptor {
	private final AttributeConverter converter;

	private Class domainType;
	private Class jdbcType;

	public AttributeConverterDescriptorNonAutoApplicableImpl(AttributeConverter converter) {
		this.converter = converter;

		final Class attributeConverterClass = converter.getClass();
		final ParameterizedType attributeConverterSignature = extractAttributeConverterParameterizedType(
				attributeConverterClass
		);
		if ( attributeConverterSignature == null ) {
			throw new AssertionFailure(
					"Could not extract ParameterizedType representation of AttributeConverter definition " +
							"from AttributeConverter implementation class [" + attributeConverterClass.getName() + "]"
			);
		}

		if ( attributeConverterSignature.getActualTypeArguments().length < 2 ) {
			throw new AnnotationException(
					"AttributeConverter [" + attributeConverterClass.getName()
							+ "] did not retain parameterized type information"
			);
		}

		if ( attributeConverterSignature.getActualTypeArguments().length > 2 ) {
			throw new AnnotationException(
					"AttributeConverter [" + attributeConverterClass.getName()
							+ "] specified more than 2 parameterized types"
			);
		}

		this.domainType = extractClass( attributeConverterSignature.getActualTypeArguments()[0] );
		if ( this.domainType == null ) {
			throw new AnnotationException(
					"Could not determine domain type from given AttributeConverter [" +
							attributeConverterClass.getName() + "]"
			);
		}

		this.jdbcType = extractClass(attributeConverterSignature.getActualTypeArguments()[1]);
		if ( this.jdbcType == null ) {
			throw new AnnotationException(
					"Could not determine JDBC type from given AttributeConverter [" +
							attributeConverterClass.getName() + "]"
			);
		}
	}

	private ParameterizedType extractAttributeConverterParameterizedType(Type base) {
		if ( base != null ) {
			Class clazz = extractClass( base );
			List types = new ArrayList();
			types.add( clazz.getGenericSuperclass() );
			types.addAll( Arrays.asList( clazz.getGenericInterfaces() ) );
			for ( Type type : types ) {
				type = resolveType( type, base );
				if ( ParameterizedType.class.isInstance( type ) ) {
					final ParameterizedType parameterizedType = (ParameterizedType) type;
					if ( AttributeConverter.class.equals( parameterizedType.getRawType() ) ) {
						return parameterizedType;
					}
				}
				ParameterizedType parameterizedType = extractAttributeConverterParameterizedType( type );
				if ( parameterizedType != null ) {
					return parameterizedType;
				}
			}
		}
		return null;
	}

	private static Class extractClass(Type type) {
		if ( type instanceof Class ) {
			return (Class) type;
		}
		else if ( type instanceof ParameterizedType ) {
			return extractClass( ( (ParameterizedType) type ).getRawType() );
		}
		return null;
	}

	private static Type resolveType(Type target, Type context) {
		if ( target instanceof ParameterizedType ) {
			return resolveParameterizedType( (ParameterizedType) target, context );
		}
		else if ( target instanceof TypeVariable ) {
			return resolveTypeVariable( (TypeVariable) target, (ParameterizedType) context );
		}
		return target;
	}

	private static ParameterizedType resolveParameterizedType(final ParameterizedType parameterizedType, Type context) {
		Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();

		final Type[] resolvedTypeArguments = new Type[actualTypeArguments.length];
		for ( int idx = 0; idx < actualTypeArguments.length; idx++ ) {
			resolvedTypeArguments[idx] = resolveType( actualTypeArguments[idx], context );
		}
		return new ParameterizedType() {

			@Override
			public Type[] getActualTypeArguments() {
				return resolvedTypeArguments;
			}

			@Override
			public Type getRawType() {
				return parameterizedType.getRawType();
			}

			@Override
			public Type getOwnerType() {
				return parameterizedType.getOwnerType();
			}

		};
	}

	private static Type resolveTypeVariable(TypeVariable typeVariable, ParameterizedType context) {
		Class clazz = extractClass( context.getRawType() );
		TypeVariable[] typeParameters = clazz.getTypeParameters();
		for ( int idx = 0; idx < typeParameters.length; idx++ ) {
			if ( typeVariable.getName().equals( typeParameters[idx].getName() ) ) {
				return resolveType( context.getActualTypeArguments()[idx], context );
			}
		}
		return typeVariable;
	}

	private static Class extractType(TypeVariable typeVariable) {
		java.lang.reflect.Type[] boundTypes = typeVariable.getBounds();
		if ( boundTypes == null || boundTypes.length != 1 ) {
			return null;
		}

		return (Class) boundTypes[0];
	}

	@Override
	public AttributeConverter getAttributeConverter() {
		return converter;
	}

	@Override
	public Class getDomainType() {
		return domainType;
	}

	@Override
	public Class getJdbcType() {
		return jdbcType;
	}

	@Override
	public boolean shouldAutoApplyToAttribute(XProperty xProperty, MetadataBuildingContext context) {
		return false;
	}

	@Override
	public boolean shouldAutoApplyToCollectionElement(XProperty xProperty, MetadataBuildingContext context) {
		return false;
	}

	@Override
	public boolean shouldAutoApplyToMapKey(XProperty xProperty, MetadataBuildingContext context) {
		return false;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy