Skip to content

Commit 89b4476

Browse files
committed
#37 - Improve MemberDetails#getElementType
1 parent e85cc87 commit 89b4476

File tree

9 files changed

+782
-6
lines changed

9 files changed

+782
-6
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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 org.hibernate.models.spi.ArrayTypeDetails;
11+
import org.hibernate.models.spi.ClassTypeDetails;
12+
import org.hibernate.models.spi.ParameterizedTypeDetails;
13+
import org.hibernate.models.spi.PrimitiveTypeDetails;
14+
import org.hibernate.models.spi.TypeDetails;
15+
import org.hibernate.models.spi.TypeVariableDetails;
16+
import org.hibernate.models.spi.TypeVariableReferenceDetails;
17+
import org.hibernate.models.spi.VoidTypeDetails;
18+
import org.hibernate.models.spi.WildcardTypeDetails;
19+
20+
/**
21+
* Switch-style handling for {@linkplain org.hibernate.models.spi.TypeDetails}
22+
*
23+
* @author Steve Ebersole
24+
*/
25+
public interface TypeDetailsSwitch<T> {
26+
T caseVoid(VoidTypeDetails voidType);
27+
28+
T casePrimitive(PrimitiveTypeDetails primitiveType);
29+
30+
T caseClass(ClassTypeDetails classType);
31+
32+
T caseArrayType(ArrayTypeDetails arrayType);
33+
34+
T caseParameterizedType(ParameterizedTypeDetails parameterizedType);
35+
36+
T caseWildcardType(WildcardTypeDetails wildcardType);
37+
38+
T caseTypeVariable(TypeVariableDetails typeVariable);
39+
40+
T caseTypeVariableReference(TypeVariableReferenceDetails typeVariableReference);
41+
42+
T defaultCase(TypeDetails type);
43+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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 org.hibernate.models.spi.ArrayTypeDetails;
11+
import org.hibernate.models.spi.ClassTypeDetails;
12+
import org.hibernate.models.spi.ParameterizedTypeDetails;
13+
import org.hibernate.models.spi.PrimitiveTypeDetails;
14+
import org.hibernate.models.spi.SourceModelBuildingContext;
15+
import org.hibernate.models.spi.TypeDetails;
16+
import org.hibernate.models.spi.TypeVariableDetails;
17+
import org.hibernate.models.spi.TypeVariableReferenceDetails;
18+
import org.hibernate.models.spi.VoidTypeDetails;
19+
import org.hibernate.models.spi.WildcardTypeDetails;
20+
21+
/**
22+
* @author Steve Ebersole
23+
*/
24+
public class TypeDetailsSwitchSupport<T> implements TypeDetailsSwitch<T> {
25+
@Override
26+
public T caseVoid(VoidTypeDetails voidType) {
27+
throw new UnsupportedOperationException( "Unexpected switch branch" );
28+
}
29+
30+
@Override
31+
public T casePrimitive(PrimitiveTypeDetails primitiveType) {
32+
throw new UnsupportedOperationException( "Unexpected switch branch" );
33+
}
34+
35+
@Override
36+
public T caseClass(ClassTypeDetails classType) {
37+
throw new UnsupportedOperationException( "Unexpected switch branch" );
38+
}
39+
40+
@Override
41+
public T caseArrayType(ArrayTypeDetails arrayType) {
42+
throw new UnsupportedOperationException( "Unexpected switch branch" );
43+
}
44+
45+
@Override
46+
public T caseParameterizedType(ParameterizedTypeDetails parameterizedType) {
47+
throw new UnsupportedOperationException( "Unexpected switch branch" );
48+
}
49+
50+
@Override
51+
public T caseWildcardType(WildcardTypeDetails wildcardType) {
52+
throw new UnsupportedOperationException( "Unexpected switch branch" );
53+
}
54+
55+
@Override
56+
public T caseTypeVariable(TypeVariableDetails typeVariable) {
57+
throw new UnsupportedOperationException( "Unexpected switch branch" );
58+
}
59+
60+
@Override
61+
public T caseTypeVariableReference(TypeVariableReferenceDetails typeVariableReference) {
62+
throw new UnsupportedOperationException( "Unexpected switch branch" );
63+
}
64+
65+
@Override
66+
public T defaultCase(TypeDetails type) {
67+
throw new UnsupportedOperationException( "Unexpected switch branch" );
68+
}
69+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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 org.hibernate.models.spi.SourceModelBuildingContext;
11+
import org.hibernate.models.spi.TypeDetails;
12+
13+
/**
14+
* Support for switch-style handling of {@linkplain org.hibernate.models.spi.TypeDetails}
15+
*
16+
* @author Steve Ebersole
17+
*/
18+
public class TypeDetailsSwitcher {
19+
public static <T> T switchType(TypeDetails type, TypeDetailsSwitch<T> typeSwitch) {
20+
21+
switch( type.getTypeKind() ) {
22+
case CLASS -> {
23+
return typeSwitch.caseClass( type.asClassType() );
24+
}
25+
case PRIMITIVE -> {
26+
return typeSwitch.casePrimitive( type.asPrimitiveType() );
27+
}
28+
case VOID -> {
29+
return typeSwitch.caseVoid( type.asVoidType() );
30+
}
31+
case ARRAY -> {
32+
return typeSwitch.caseArrayType( type.asArrayType() );
33+
}
34+
case PARAMETERIZED_TYPE -> {
35+
return typeSwitch.caseParameterizedType( type.asParameterizedType() );
36+
}
37+
case WILDCARD_TYPE -> {
38+
return typeSwitch.caseWildcardType( type.asWildcardType() );
39+
}
40+
case TYPE_VARIABLE -> {
41+
return typeSwitch.caseTypeVariable( type.asTypeVariable() );
42+
}
43+
case TYPE_VARIABLE_REFERENCE -> {
44+
return typeSwitch.caseTypeVariableReference( type.asTypeVariableReference() );
45+
}
46+
default -> {
47+
return typeSwitch.defaultCase( type );
48+
}
49+
}
50+
}
51+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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.spi;
9+
10+
import java.util.Collection;
11+
12+
import org.hibernate.models.internal.TypeDetailsSwitchSupport;
13+
import org.hibernate.models.internal.TypeDetailsSwitcher;
14+
15+
/**
16+
* Used to determine the type details for a Collection element - see {@linkplain #extractCollectionElementType(TypeDetails)}
17+
*
18+
* @author Steve Ebersole
19+
*/
20+
public class CollectionElementSwitch extends TypeDetailsSwitchSupport<TypeDetails> {
21+
22+
public static TypeDetails extractCollectionElementType(TypeDetails memberType) {
23+
assert memberType.isImplementor( Collection.class );
24+
25+
// we may need to handle "concrete types" such as `class SpecialList implements List<String>`
26+
final ClassDetails rawClassDetails = memberType.determineRawClass();
27+
final CollectionElementSwitch collectionElementSwitch = new CollectionElementSwitch( memberType );
28+
29+
// first, check super-type...
30+
if ( rawClassDetails.getGenericSuperType() != null ) {
31+
final TypeDetails typeDetails = TypeDetailsSwitcher.switchType( rawClassDetails.getGenericSuperType(), collectionElementSwitch );
32+
if ( typeDetails != null ) {
33+
return typeDetails;
34+
}
35+
}
36+
37+
// then, interfaces...
38+
for ( TypeDetails implementedInterface : rawClassDetails.getImplementedInterfaces() ) {
39+
final TypeDetails typeDetails = TypeDetailsSwitcher.switchType( implementedInterface, collectionElementSwitch );
40+
if ( typeDetails != null ) {
41+
return typeDetails;
42+
}
43+
}
44+
45+
// otherwise, assume Object
46+
return ClassBasedTypeDetails.OBJECT_TYPE_DETAILS;
47+
}
48+
49+
private final TypeDetails memberTypeDetails;
50+
51+
private CollectionElementSwitch(TypeDetails memberTypeDetails) {
52+
this.memberTypeDetails = memberTypeDetails;
53+
}
54+
55+
@Override
56+
public TypeDetails caseClass(ClassTypeDetails classType) {
57+
if ( classType.isImplementor( Collection.class ) ) {
58+
if ( classType.getClassDetails().getGenericSuperType() != null ) {
59+
return TypeDetailsSwitcher.switchType( classType.getClassDetails().getGenericSuperType(), this );
60+
}
61+
}
62+
return null;
63+
}
64+
65+
@Override
66+
public TypeDetails caseParameterizedType(ParameterizedTypeDetails parameterizedType) {
67+
if ( parameterizedType.isImplementor( Collection.class ) ) {
68+
return parameterizedType.getArguments().get( 0 );
69+
}
70+
return null;
71+
}
72+
73+
@Override
74+
public TypeDetails caseWildcardType(WildcardTypeDetails wildcardType) {
75+
if ( wildcardType.isImplementor( Collection.class ) ) {
76+
return wildcardType.getBound();
77+
}
78+
return null;
79+
}
80+
81+
@Override
82+
public TypeDetails caseTypeVariable(TypeVariableDetails typeVariable) {
83+
if ( typeVariable.isImplementor( Collection.class ) ) {
84+
return memberTypeDetails.resolveTypeVariable( typeVariable.getIdentifier() );
85+
}
86+
return null;
87+
}
88+
89+
@Override
90+
public TypeDetails caseTypeVariableReference(TypeVariableReferenceDetails typeVariableReference) {
91+
if ( typeVariableReference.isImplementor( Collection.class ) ) {
92+
return memberTypeDetails.resolveTypeVariable( typeVariableReference.getIdentifier() );
93+
}
94+
return null;
95+
}
96+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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.spi;
9+
10+
import java.util.Map;
11+
12+
import org.hibernate.models.internal.TypeDetailsSwitchSupport;
13+
import org.hibernate.models.internal.TypeDetailsSwitcher;
14+
15+
/**
16+
* Used to determine the type details for a Map key - see {@linkplain #extractMapKeyType(TypeDetails)}
17+
*
18+
* @author Steve Ebersole
19+
*/
20+
public class MapKeySwitch extends TypeDetailsSwitchSupport<TypeDetails> {
21+
22+
public static TypeDetails extractMapKeyType(TypeDetails memberType) {
23+
assert memberType.isImplementor( Map.class );
24+
25+
// we may need to handle "concrete types" such as `class SpecialList implements List<String>`
26+
final ClassDetails rawClassDetails = memberType.determineRawClass();
27+
final MapKeySwitch mapKeySwitch = new MapKeySwitch( memberType );
28+
29+
// first, check super-type...
30+
if ( rawClassDetails.getGenericSuperType() != null ) {
31+
final TypeDetails typeDetails = TypeDetailsSwitcher.switchType( rawClassDetails.getGenericSuperType(), mapKeySwitch );
32+
if ( typeDetails != null ) {
33+
return typeDetails;
34+
}
35+
}
36+
37+
// then, interfaces...
38+
for ( TypeDetails implementedInterface : rawClassDetails.getImplementedInterfaces() ) {
39+
final TypeDetails typeDetails = TypeDetailsSwitcher.switchType( implementedInterface, mapKeySwitch );
40+
if ( typeDetails != null ) {
41+
return typeDetails;
42+
}
43+
}
44+
45+
// otherwise, assume Object
46+
return ClassBasedTypeDetails.OBJECT_TYPE_DETAILS;
47+
}
48+
49+
private final TypeDetails memberTypeDetails;
50+
51+
private MapKeySwitch(TypeDetails memberTypeDetails) {
52+
this.memberTypeDetails = memberTypeDetails;
53+
}
54+
55+
@Override
56+
public TypeDetails caseClass(ClassTypeDetails classType) {
57+
if ( classType.isImplementor( Map.class ) ) {
58+
if ( classType.getClassDetails().getGenericSuperType() != null ) {
59+
return TypeDetailsSwitcher.switchType( classType.getClassDetails().getGenericSuperType(), this );
60+
}
61+
}
62+
return null;
63+
}
64+
65+
@Override
66+
public TypeDetails caseParameterizedType(ParameterizedTypeDetails parameterizedType) {
67+
if ( parameterizedType.isImplementor( Map.class ) ) {
68+
return parameterizedType.getArguments().get( 0 );
69+
}
70+
return null;
71+
}
72+
73+
@Override
74+
public TypeDetails caseWildcardType(WildcardTypeDetails wildcardType) {
75+
if ( wildcardType.isImplementor( Map.class ) ) {
76+
return wildcardType.getBound();
77+
}
78+
return null;
79+
}
80+
81+
@Override
82+
public TypeDetails caseTypeVariable(TypeVariableDetails typeVariable) {
83+
if ( typeVariable.isImplementor( Map.class ) ) {
84+
return memberTypeDetails.resolveTypeVariable( typeVariable.getIdentifier() );
85+
}
86+
return null;
87+
}
88+
89+
@Override
90+
public TypeDetails caseTypeVariableReference(TypeVariableReferenceDetails typeVariableReference) {
91+
if ( typeVariableReference.isImplementor( Map.class ) ) {
92+
return memberTypeDetails.resolveTypeVariable( typeVariableReference.getIdentifier() );
93+
}
94+
return null;
95+
}
96+
}

0 commit comments

Comments
 (0)