Skip to content

Commit 8639ee5

Browse files
committed
HHH-19626 Properly resolving generic parameter type in subclass
1 parent d989466 commit 8639ee5

File tree

3 files changed

+84
-1
lines changed

3 files changed

+84
-1
lines changed

tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import static java.beans.Introspector.decapitalize;
6868
import static java.lang.Boolean.FALSE;
6969
import static java.util.Collections.emptyList;
70+
import static java.util.Objects.requireNonNullElse;
7071
import static java.util.stream.Collectors.toList;
7172
import static javax.lang.model.util.ElementFilter.fieldsIn;
7273
import static javax.lang.model.util.ElementFilter.methodsIn;
@@ -100,6 +101,7 @@
100101
import static org.hibernate.processor.util.TypeUtils.implementsInterface;
101102
import static org.hibernate.processor.util.TypeUtils.primitiveClassMatchesKind;
102103
import static org.hibernate.processor.util.TypeUtils.propertyName;
104+
import static org.hibernate.processor.util.TypeUtils.resolveTypeMirror;
103105

104106
/**
105107
* Class used to collect meta information about an annotated type (entity, embeddable or mapped superclass).
@@ -2526,7 +2528,15 @@ enum FieldType {
25262528
return null;
25272529
}
25282530

2529-
if ( checkParameterType( entityType, param, memberType( member ) ) ) {
2531+
final var memberType = memberType( member );
2532+
final var attributeType = requireNonNullElse(
2533+
resolveTypeMirror(
2534+
entityType,
2535+
member.getEnclosingElement(),
2536+
memberType.toString()
2537+
), memberType
2538+
);
2539+
if ( checkParameterType( entityType, param, attributeType ) ) {
25302540
return FieldType.MULTIVALUED;
25312541
}
25322542
else if ( containsAnnotation( param, PATTERN ) ) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.processor.util;
6+
7+
import javax.lang.model.element.Element;
8+
import javax.lang.model.element.TypeElement;
9+
import javax.lang.model.type.DeclaredType;
10+
import javax.lang.model.type.TypeMirror;
11+
import java.util.HashMap;
12+
import java.util.Map;
13+
14+
public class GenericTypeParameterResolver {
15+
16+
private final Map<Element, Map<String, TypeMirror>> typeParameterMap;
17+
18+
public GenericTypeParameterResolver(TypeElement element) {
19+
typeParameterMap = new HashMap<>();
20+
resolveTypeParameters( element, Map.of() );
21+
}
22+
23+
public String resolveTypeName(Element el, String name) {
24+
final var mirror = resolveTypeMirror( el, name );
25+
return mirror == null ? name : mirror.toString();
26+
}
27+
28+
public TypeMirror resolveTypeMirror(Element el, String name) {
29+
return typeParameterMap.getOrDefault( el, Map.of() ).get( name );
30+
}
31+
32+
public void resolveTypeParameters(TypeElement element, Map<String, TypeMirror> map) {
33+
resolveElementTypeParameters( element.getSuperclass(), map );
34+
element.getInterfaces().forEach( iface -> resolveElementTypeParameters( iface, map ) );
35+
}
36+
37+
private void resolveElementTypeParameters(TypeMirror type, Map<String, TypeMirror> parametersMap) {
38+
if ( type instanceof DeclaredType declaredType
39+
&& declaredType.asElement() instanceof TypeElement typeElement ) {
40+
final var generic = typeElement.getTypeParameters();
41+
final var map = new HashMap<String, TypeMirror>();
42+
var typeArguments = declaredType.getTypeArguments();
43+
if ( !( typeArguments.isEmpty() || generic.size() == typeArguments.size() ) ) {
44+
throw new IndexOutOfBoundsException(
45+
"Type %s : %d vs %d".formatted( type, generic.size(), typeArguments.size() ) );
46+
}
47+
for ( var n = 0; n < generic.size(); ++n ) {
48+
final var mirror = typeArguments.isEmpty()
49+
? generic.get( 0 ).getBounds().get( 0 )
50+
: typeArguments.get( n );
51+
final var value = mirror.toString();
52+
map.put( generic.get( n ).toString(), parametersMap.getOrDefault( value, mirror ) );
53+
}
54+
typeParameterMap.put( typeElement, map );
55+
resolveTypeParameters( typeElement, map );
56+
}
57+
}
58+
}

tooling/metamodel-generator/src/main/java/org/hibernate/processor/util/TypeUtils.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ public final class TypeUtils {
9494
PRIMITIVES.put( TypeKind.DOUBLE, "double" );
9595
}
9696

97+
private static final Map<Element, GenericTypeParameterResolver> typeResolversMap = new HashMap<>();
98+
9799
private TypeUtils() {
98100
}
99101

@@ -779,4 +781,17 @@ public static boolean isPrimitive(String paramType) {
779781

780782
public static final Set<String> PRIMITIVE_TYPES =
781783
Set.of("boolean", "char", "long", "int", "short", "byte", "double", "float");
784+
785+
private static GenericTypeParameterResolver getTypeParameterResolver(TypeElement typeElement) {
786+
final GenericTypeParameterResolver typeParameterResolver = typeResolversMap.get( typeElement );
787+
if ( typeParameterResolver != null ) {
788+
return typeParameterResolver;
789+
}
790+
return new GenericTypeParameterResolver( typeElement );
791+
}
792+
793+
public static TypeMirror resolveTypeMirror(TypeElement typeElement, Element element, String name) {
794+
final var typeParameterResolver = getTypeParameterResolver( typeElement );
795+
return typeParameterResolver.resolveTypeMirror( element, name );
796+
}
782797
}

0 commit comments

Comments
 (0)