org.hibernate.boot.internal.AttributeConverterDescriptorNonAutoApplicableImpl Maven / Gradle / Ivy
/*
* 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;
}
}