Skip to content

Commit bb2833b

Browse files
Sveinsebersole
authored andcommitted
HHH-8854 Resolve any TypeVariables to Class or ParameterizedType when
creating AttributeConverterDefinition
1 parent b584513 commit bb2833b

File tree

2 files changed

+87
-1
lines changed

2 files changed

+87
-1
lines changed

hibernate-core/src/main/java/org/hibernate/cfg/AttributeConverterDefinition.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ private ParameterizedType extractAttributeConverterParameterizedType(Type base)
156156
types.add( clazz.getGenericSuperclass() );
157157
types.addAll( Arrays.asList( clazz.getGenericInterfaces() ) );
158158
for ( Type type : types ) {
159+
type = resolveType( type, base );
159160
if ( ParameterizedType.class.isInstance( type ) ) {
160161
final ParameterizedType parameterizedType = (ParameterizedType) type;
161162
if ( AttributeConverter.class.equals( parameterizedType.getRawType() ) ) {
@@ -171,6 +172,54 @@ private ParameterizedType extractAttributeConverterParameterizedType(Type base)
171172
return null;
172173
}
173174

175+
private static Type resolveType(Type target, Type context) {
176+
if ( target instanceof ParameterizedType ) {
177+
return resolveParameterizedType( (ParameterizedType) target, context );
178+
}
179+
else if ( target instanceof TypeVariable ) {
180+
return resolveTypeVariable( (TypeVariable) target, (ParameterizedType) context );
181+
}
182+
return target;
183+
}
184+
185+
private static ParameterizedType resolveParameterizedType(final ParameterizedType parameterizedType, Type context) {
186+
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
187+
188+
final Type[] resolvedTypeArguments = new Type[actualTypeArguments.length];
189+
for ( int idx = 0; idx < actualTypeArguments.length; idx++ ) {
190+
resolvedTypeArguments[idx] = resolveType( actualTypeArguments[idx], context );
191+
}
192+
return new ParameterizedType() {
193+
194+
@Override
195+
public Type[] getActualTypeArguments() {
196+
return resolvedTypeArguments;
197+
}
198+
199+
@Override
200+
public Type getRawType() {
201+
return parameterizedType.getRawType();
202+
}
203+
204+
@Override
205+
public Type getOwnerType() {
206+
return parameterizedType.getOwnerType();
207+
}
208+
209+
};
210+
}
211+
212+
private static Type resolveTypeVariable(TypeVariable typeVariable, ParameterizedType context) {
213+
Class clazz = extractClass( context.getRawType() );
214+
TypeVariable[] typeParameters = clazz.getTypeParameters();
215+
for ( int idx = 0; idx < typeParameters.length; idx++ ) {
216+
if ( typeVariable.getName().equals( typeParameters[idx].getName() ) ) {
217+
return resolveType( context.getActualTypeArguments()[idx], context );
218+
}
219+
}
220+
return typeVariable;
221+
}
222+
174223
public AttributeConverter getAttributeConverter() {
175224
return attributeConverter;
176225
}

hibernate-core/src/test/java/org/hibernate/test/type/AttributeConverterOnSuperclassTest.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import static org.junit.Assert.assertEquals;
44

5+
import java.util.List;
6+
57
import javax.persistence.AttributeConverter;
68

79
import org.hibernate.cfg.AttributeConverterDefinition;
@@ -11,7 +13,8 @@
1113

1214
/**
1315
* Test the ability to interpret and understand AttributeConverter impls when the base class does not
14-
* explicitly implement AttributeConverter but implements it via an interface or superclass.
16+
* explicitly implement AttributeConverter but implements it via an interface or superclass. This also
17+
* involves resolving any TypeVariables to Class or ParameterizedType.
1518
*
1619
* @author Svein Baardsen
1720
*/
@@ -62,4 +65,38 @@ public void testAttributeConverterOnInterface() {
6265
assertEquals( String.class, def.getEntityAttributeType() );
6366
}
6467

68+
public static class NoopAttributeConverter<T> implements AttributeConverter<T, T> {
69+
70+
@Override
71+
public T convertToDatabaseColumn(T attribute) {
72+
return attribute;
73+
}
74+
75+
@Override
76+
public T convertToEntityAttribute(T dbData) {
77+
return dbData;
78+
}
79+
}
80+
81+
public static class StringNoopAttributeConverter extends NoopAttributeConverter<String> {
82+
}
83+
84+
@Test
85+
public void testTypeVariableAttributeConverterTypeArguments() {
86+
AttributeConverterDefinition def = AttributeConverterDefinition.from( StringNoopAttributeConverter.class );
87+
assertEquals( String.class, def.getEntityAttributeType() );
88+
}
89+
90+
public static class ListNoopAttributeConverter<T> extends NoopAttributeConverter<List<T>> {
91+
}
92+
93+
public static class StringListNoopAttributeConverter extends ListNoopAttributeConverter<String> {
94+
}
95+
96+
@Test
97+
public void testParameterizedTypeWithTypeVariableAttributeConverterTypeArguments() {
98+
AttributeConverterDefinition def = AttributeConverterDefinition.from( StringListNoopAttributeConverter.class );
99+
assertEquals( List.class, def.getEntityAttributeType() );
100+
}
101+
65102
}

0 commit comments

Comments
 (0)