Skip to content

Commit ed518a0

Browse files
committed
#23 - Add TypeDetails#isResolved
1 parent a326cce commit ed518a0

12 files changed

+298
-21
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
* Copyright: Red Hat Inc. and Hibernate Authors
6+
*/
7+
8+
package org.hibernate.models.internal;
9+
10+
import java.util.List;
11+
import java.util.Objects;
12+
13+
import org.hibernate.models.spi.ArrayTypeDetails;
14+
import org.hibernate.models.spi.ClassDetails;
15+
import org.hibernate.models.spi.ClassTypeDetails;
16+
import org.hibernate.models.spi.ParameterizedTypeDetails;
17+
import org.hibernate.models.spi.PrimitiveTypeDetails;
18+
import org.hibernate.models.spi.SourceModelBuildingContext;
19+
import org.hibernate.models.spi.TypeDetails;
20+
import org.hibernate.models.spi.TypeDetailsSwitch;
21+
import org.hibernate.models.spi.TypeVariableDetails;
22+
import org.hibernate.models.spi.TypeVariableReferenceDetails;
23+
import org.hibernate.models.spi.VoidTypeDetails;
24+
import org.hibernate.models.spi.WildcardTypeDetails;
25+
26+
/**
27+
* TypeDetailsSwitch implementation checking whether a type is resolved (all of its bounds are known)
28+
*
29+
* @author Steve Ebersole
30+
*/
31+
public class IsResolvedTypeSwitch implements TypeDetailsSwitch<Boolean> {
32+
public static final IsResolvedTypeSwitch IS_RESOLVED_SWITCH = new IsResolvedTypeSwitch();
33+
34+
public static boolean isBound(TypeDetails typeDetails, SourceModelBuildingContext buildingContext) {
35+
return TypeDetailsSwitch.switchType( typeDetails, IS_RESOLVED_SWITCH, buildingContext );
36+
}
37+
38+
@Override
39+
public Boolean caseClass(ClassTypeDetails classType, SourceModelBuildingContext buildingContext) {
40+
// not completely kosher, but works for our needs
41+
//noinspection RedundantIfStatement
42+
if ( Objects.equals( classType.getClassDetails(), ClassDetails.OBJECT_CLASS_DETAILS ) ) {
43+
return false;
44+
}
45+
return true;
46+
}
47+
48+
@Override
49+
public Boolean casePrimitive(PrimitiveTypeDetails primitiveType, SourceModelBuildingContext buildingContext) {
50+
return true;
51+
}
52+
53+
@Override
54+
public Boolean caseVoid(VoidTypeDetails voidType, SourceModelBuildingContext buildingContext) {
55+
return true;
56+
}
57+
58+
@Override
59+
public Boolean caseArrayType(ArrayTypeDetails arrayType, SourceModelBuildingContext buildingContext) {
60+
return isBound( arrayType.getConstituentType(), buildingContext );
61+
}
62+
63+
@Override
64+
public Boolean caseParameterizedType(
65+
ParameterizedTypeDetails parameterizedType,
66+
SourceModelBuildingContext buildingContext) {
67+
final List<TypeDetails> typeArgs = parameterizedType.getArguments();
68+
for ( TypeDetails arg : typeArgs ) {
69+
if ( !isBound( arg, buildingContext ) ) {
70+
return false;
71+
}
72+
}
73+
return true;
74+
}
75+
76+
@Override
77+
public Boolean caseWildcardType(WildcardTypeDetails wildcardType, SourceModelBuildingContext buildingContext) {
78+
return isBound( wildcardType.getBound(), buildingContext );
79+
}
80+
81+
@Override
82+
public Boolean caseTypeVariable(TypeVariableDetails typeVariable, SourceModelBuildingContext buildingContext) {
83+
for ( TypeDetails bound : typeVariable.getBounds() ) {
84+
if ( !isBound( bound, buildingContext ) ) {
85+
return false;
86+
}
87+
}
88+
return true;
89+
}
90+
91+
@Override
92+
public Boolean caseTypeVariableReference(
93+
TypeVariableReferenceDetails typeVariableReference,
94+
SourceModelBuildingContext buildingContext) {
95+
return true;
96+
}
97+
98+
@Override
99+
public Boolean defaultCase(TypeDetails type, SourceModelBuildingContext buildingContext) {
100+
throw new UnsupportedOperationException( "Unexpected attribute type - " + type );
101+
}
102+
}

src/main/java/org/hibernate/models/internal/ParameterizedTypeDetailsImpl.java

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import org.hibernate.models.spi.ClassDetails;
1313
import org.hibernate.models.spi.ParameterizedTypeDetails;
1414
import org.hibernate.models.spi.TypeDetails;
15-
import org.hibernate.models.spi.TypeDetailsHelper;
1615
import org.hibernate.models.spi.TypeVariableDetails;
1716

1817
/**

src/main/java/org/hibernate/models/internal/jandex/JandexMethodDetails.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ public Method toJavaMember() {
134134
@Override
135135
public TypeDetails resolveRelativeType(TypeDetails container) {
136136
if ( methodKind == GETTER || methodKind == SETTER ) {
137-
return TypeDetailsHelper.resolveRelativeType( type, container );
137+
return type.determineRelativeType( container );
138138
}
139139
throw new IllegalStateException( "Method does not have a type - " + this );
140140
}

src/main/java/org/hibernate/models/internal/jandex/JandexTypeSwitchStandard.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,13 @@
1313
import java.util.Collections;
1414
import java.util.List;
1515

16-
import org.hibernate.models.internal.ArrayTypeDetailsImpl;
1716
import org.hibernate.models.internal.ClassTypeDetailsImpl;
1817
import org.hibernate.models.internal.ParameterizedTypeDetailsImpl;
1918
import org.hibernate.models.internal.PrimitiveTypeDetailsImpl;
2019
import org.hibernate.models.internal.TypeVariableDetailsImpl;
2120
import org.hibernate.models.internal.TypeVariableReferenceDetailsImpl;
2221
import org.hibernate.models.internal.VoidTypeDetailsImpl;
2322
import org.hibernate.models.internal.WildcardTypeDetailsImpl;
24-
import org.hibernate.models.internal.jdk.JdkTrackingTypeSwitch;
2523
import org.hibernate.models.internal.util.CollectionHelper;
2624
import org.hibernate.models.spi.ClassDetails;
2725
import org.hibernate.models.spi.SourceModelBuildingContext;
@@ -42,6 +40,8 @@
4240
import static org.hibernate.models.internal.util.CollectionHelper.arrayList;
4341

4442
/**
43+
* JandexTypeSwitch implementation which builds corresponding {@linkplain TypeDetails} references
44+
*
4545
* @author Steve Ebersole
4646
*/
4747
public class JandexTypeSwitchStandard implements JandexTypeSwitch<TypeDetails> {

src/main/java/org/hibernate/models/internal/jdk/JdkMethodDetails.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ public Method toJavaMember() {
126126
@Override
127127
public TypeDetails resolveRelativeType(TypeDetails container) {
128128
if ( methodKind == GETTER || methodKind == SETTER ) {
129-
return TypeDetailsHelper.resolveRelativeType( type, container );
129+
return type.determineRelativeType( container );
130130
}
131131

132132
throw new IllegalStateException( "Method does not have a type - " + this );

src/main/java/org/hibernate/models/spi/MemberDetails.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ default boolean isField() {
227227
* getters, setters and record components.
228228
*/
229229
default TypeDetails resolveRelativeType(TypeDetails container) {
230-
return TypeDetailsHelper.resolveRelativeType( getType(), container );
230+
return getType().determineRelativeType( container );
231231
}
232232

233233
/**
@@ -236,7 +236,7 @@ default TypeDetails resolveRelativeType(TypeDetails container) {
236236
* @see #resolveRelativeType(TypeDetails)
237237
*/
238238
default TypeDetails resolveRelativeType(ClassDetails container) {
239-
return TypeDetailsHelper.resolveRelativeType( getType(), container );
239+
return getType().determineRelativeType( container );
240240
}
241241

242242
/**

src/main/java/org/hibernate/models/spi/TypeDetails.java

+47
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
package org.hibernate.models.spi;
99

10+
import static org.hibernate.models.internal.IsResolvedTypeSwitch.IS_RESOLVED_SWITCH;
11+
import static org.hibernate.models.spi.TypeDetailsSwitch.switchType;
12+
1013
/**
1114
* Abstraction for what Hibernate understands about a "type", generally before it has access to
1215
* the actual {@link java.lang.reflect.Type} reference.
@@ -89,6 +92,50 @@ default WildcardTypeDetails asWildcardType() {
8992
throw new IllegalArgumentException( "Not a wildcard type - " + this );
9093
}
9194

95+
/**
96+
* Determine whether all the bounds (if any) of the type are concretely known
97+
* <p/>
98+
* For example, given:
99+
* <pre class="brush:java">
100+
* class {@code Thing<T>} {
101+
* T id;
102+
* }
103+
* class {@code AnotherThing extends Thing<Integer>} {
104+
* }
105+
* </pre>
106+
* The type for {@code id} {@linkplain TypeDetails#determineRelativeType relative} to {@code Thing} is NOT resolved
107+
* whereas the type for {@code id} relative to {@code AnotherThing} is.
108+
*/
109+
default boolean isResolved() {
110+
// IMPORTANT : Relies on the fact that `IsResolvedTypeSwitch` never uses the
111+
// `SourceModelBuildingContext` passed to it as a `TypeDetailsSwitch` implementation.
112+
// Hence, the passing `null` here
113+
return switchType( this, IS_RESOLVED_SWITCH, null );
114+
}
115+
116+
/**
117+
* Determine the type relative to the passed {@code container}.
118+
* <p/>
119+
* For example, given the classes defined in {@linkplain #isResolved()}, calling
120+
* this method has the following outcomes based on the passed {@code container} - <ul>
121+
* <li>Passing {@code Thing}, the result would be the {@code ParameterizedTypeDetails(T)}</li>
122+
* <li>Passing {@code AnotherThing}, the result would be {@code ClassTypeDetails(Integer)}</li>
123+
* </ul>
124+
*/
125+
default TypeDetails determineRelativeType(TypeDetails container) {
126+
return TypeDetailsHelper.resolveRelativeType( this, container );
127+
}
128+
129+
/**
130+
* Determine the type relative to the passed {@code container}.
131+
* <p/>
132+
* Overload of {@linkplain #determineRelativeType(TypeDetails)}
133+
*/
134+
default TypeDetails determineRelativeType(ClassDetails container) {
135+
return TypeDetailsHelper.resolveRelativeType( this, container );
136+
}
137+
138+
92139
enum Kind {
93140

94141
/**

src/main/java/org/hibernate/models/spi/TypeDetailsHelper.java

+44-4
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,29 @@
1414
import org.hibernate.models.internal.util.CollectionHelper;
1515

1616
/**
17+
* Helper utilities for dealing with {@linkplain TypeDetails}
18+
*
1719
* @author Steve Ebersole
1820
*/
1921
public class TypeDetailsHelper {
22+
/**
23+
* Given an attribute member type and a concrete container type, resolve the type of
24+
* the attribute relative to that container.
25+
* <p/>
26+
* For example, consider
27+
* <pre class="brush:java">
28+
* class {@code Item<T>} {
29+
* T id;
30+
* }
31+
* class Hat extends {@code Item<Integer} {
32+
* ...
33+
* }
34+
* </pre>
35+
* Given this model, a call to resolve the type of {@code id} relative to {@code Hat}
36+
* will return {@code ClassTypeDetails(Integer)}. A call to resolve the type of {@code id}
37+
* relative to {@code Item} returns {@code ParameterizedTypeDetails(T)} (roughly Object)
38+
*/
39+
@SuppressWarnings("RedundantLabeledSwitchRuleCodeBlock")
2040
public static TypeDetails resolveRelativeType(TypeDetails type, TypeDetails container) {
2141
switch ( type.getTypeKind() ) {
2242
case CLASS, PRIMITIVE, VOID, ARRAY -> {
@@ -67,6 +87,10 @@ public static TypeVariableDetails findTypeVariableDetails2(String identifier, Li
6787
return null;
6888
}
6989

90+
/**
91+
* Overload of {@linkplain #resolveRelativeType(TypeDetails, TypeDetails)}
92+
*/
93+
@SuppressWarnings("RedundantLabeledSwitchRuleCodeBlock")
7094
public static TypeDetails resolveRelativeType(TypeDetails memberType, ClassDetails containerType) {
7195
switch ( memberType.getTypeKind() ) {
7296
case CLASS, PRIMITIVE, VOID, ARRAY -> {
@@ -91,6 +115,12 @@ public static TypeDetails resolveRelativeType(TypeDetails memberType, ClassDetai
91115
}
92116
}
93117

118+
/**
119+
* Very much the same as {@linkplain #resolveRelativeType(TypeDetails, TypeDetails)}, except that
120+
* here we resolve the relative type to the corresponding {@link ClassBasedTypeDetails} which
121+
* gives easy access to the type's {@linkplain ClassBasedTypeDetails#getClassDetails() ClassDetails}
122+
*/
123+
@SuppressWarnings("RedundantLabeledSwitchRuleCodeBlock")
94124
public static ClassBasedTypeDetails resolveRelativeClassType(TypeDetails memberType, TypeDetails containerType) {
95125
switch ( memberType.getTypeKind() ) {
96126
case CLASS, PRIMITIVE, VOID, ARRAY -> {
@@ -121,20 +151,24 @@ else if ( typeDetails.getTypeKind() == TypeDetails.Kind.TYPE_VARIABLE ) {
121151
}
122152
}
123153
case TYPE_VARIABLE_REFERENCE -> {
124-
throw new UnsupportedOperationException( "TypeVariableReferenceDetails not supported for relative type resolution" );
154+
throw new UnsupportedOperationException( "TypeVariableReferenceDetails not supported for relative class resolution" );
125155
}
126156
case PARAMETERIZED_TYPE -> {
127-
throw new UnsupportedOperationException( "ParameterizedTypeDetails not supported for relative type resolution" );
157+
throw new UnsupportedOperationException( "ParameterizedTypeDetails not supported for relative class resolution" );
128158
}
129159
case WILDCARD_TYPE -> {
130-
throw new UnsupportedOperationException( "WildcardTypeDetails not supported for relative type resolution" );
160+
throw new UnsupportedOperationException( "WildcardTypeDetails not supported for relative class resolution" );
131161
}
132162
default -> {
133163
throw new UnsupportedOperationException( "Unknown TypeDetails kind - " + memberType.getTypeKind() );
134164
}
135165
}
136166
}
137167

168+
/**
169+
* Overload form of {@linkplain #resolveRelativeClassType(TypeDetails, TypeDetails)}
170+
*/
171+
@SuppressWarnings("RedundantLabeledSwitchRuleCodeBlock")
138172
public static ClassBasedTypeDetails resolveRelativeClassType(TypeDetails memberType, ClassDetails containerType) {
139173
switch ( memberType.getTypeKind() ) {
140174
case CLASS, PRIMITIVE, VOID, ARRAY -> {
@@ -179,9 +213,12 @@ else if ( typeDetails.getTypeKind() == TypeDetails.Kind.TYPE_VARIABLE ) {
179213
}
180214
}
181215

216+
/**
217+
* Given a type, resolve the underlying ClassDetails
218+
*/
182219
public static ClassDetails resolveRawClass(
183220
TypeDetails typeDetails,
184-
SourceModelBuildingContext buildingContext) {
221+
@SuppressWarnings("unused") SourceModelBuildingContext buildingContext) {
185222
switch ( typeDetails.getTypeKind() ) {
186223
case CLASS, PRIMITIVE, VOID, ARRAY -> {
187224
return ( (ClassBasedTypeDetails) typeDetails ).getClassDetails();
@@ -206,6 +243,9 @@ public static ClassDetails resolveRawClass(
206243
return ClassDetails.OBJECT_CLASS_DETAILS;
207244
}
208245

246+
/**
247+
* Make an array type of the given component type
248+
*/
209249
public static ArrayTypeDetails arrayOf(TypeDetails constituentType, SourceModelBuildingContext buildingContext) {
210250
final ClassDetails arrayClassDetails;
211251
if ( constituentType.getTypeKind() == TypeDetails.Kind.PRIMITIVE ) {

0 commit comments

Comments
 (0)