HHH-8854 Resolve any TypeVariables to Class or ParameterizedType when

creating AttributeConverterDefinition
This commit is contained in:
Svein 2015-05-15 09:54:09 +02:00 committed by Steve Ebersole
parent b5845138e6
commit bb2833bafc
2 changed files with 87 additions and 1 deletions

View File

@ -156,6 +156,7 @@ public class AttributeConverterDefinition {
types.add( clazz.getGenericSuperclass() ); types.add( clazz.getGenericSuperclass() );
types.addAll( Arrays.asList( clazz.getGenericInterfaces() ) ); types.addAll( Arrays.asList( clazz.getGenericInterfaces() ) );
for ( Type type : types ) { for ( Type type : types ) {
type = resolveType( type, base );
if ( ParameterizedType.class.isInstance( type ) ) { if ( ParameterizedType.class.isInstance( type ) ) {
final ParameterizedType parameterizedType = (ParameterizedType) type; final ParameterizedType parameterizedType = (ParameterizedType) type;
if ( AttributeConverter.class.equals( parameterizedType.getRawType() ) ) { if ( AttributeConverter.class.equals( parameterizedType.getRawType() ) ) {
@ -171,6 +172,54 @@ public class AttributeConverterDefinition {
return null; 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;
}
public AttributeConverter getAttributeConverter() { public AttributeConverter getAttributeConverter() {
return attributeConverter; return attributeConverter;
} }

View File

@ -2,6 +2,8 @@ package org.hibernate.test.type;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import java.util.List;
import javax.persistence.AttributeConverter; import javax.persistence.AttributeConverter;
import org.hibernate.cfg.AttributeConverterDefinition; import org.hibernate.cfg.AttributeConverterDefinition;
@ -11,7 +13,8 @@ import org.junit.Test;
/** /**
* Test the ability to interpret and understand AttributeConverter impls when the base class does not * Test the ability to interpret and understand AttributeConverter impls when the base class does not
* explicitly implement AttributeConverter but implements it via an interface or superclass. * explicitly implement AttributeConverter but implements it via an interface or superclass. This also
* involves resolving any TypeVariables to Class or ParameterizedType.
* *
* @author Svein Baardsen * @author Svein Baardsen
*/ */
@ -62,4 +65,38 @@ public class AttributeConverterOnSuperclassTest extends BaseUnitTestCase {
assertEquals( String.class, def.getEntityAttributeType() ); assertEquals( String.class, def.getEntityAttributeType() );
} }
public static class NoopAttributeConverter<T> implements AttributeConverter<T, T> {
@Override
public T convertToDatabaseColumn(T attribute) {
return attribute;
}
@Override
public T convertToEntityAttribute(T dbData) {
return dbData;
}
}
public static class StringNoopAttributeConverter extends NoopAttributeConverter<String> {
}
@Test
public void testTypeVariableAttributeConverterTypeArguments() {
AttributeConverterDefinition def = AttributeConverterDefinition.from( StringNoopAttributeConverter.class );
assertEquals( String.class, def.getEntityAttributeType() );
}
public static class ListNoopAttributeConverter<T> extends NoopAttributeConverter<List<T>> {
}
public static class StringListNoopAttributeConverter extends ListNoopAttributeConverter<String> {
}
@Test
public void testParameterizedTypeWithTypeVariableAttributeConverterTypeArguments() {
AttributeConverterDefinition def = AttributeConverterDefinition.from( StringListNoopAttributeConverter.class );
assertEquals( List.class, def.getEntityAttributeType() );
}
} }