1
1
/*
2
- * Copyright 2012-2023 the original author or authors.
2
+ * Copyright 2012-2025 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
17
17
package org .springframework .boot .configurationprocessor ;
18
18
19
19
import java .time .Duration ;
20
+ import java .util .Map ;
20
21
import java .util .function .BiConsumer ;
21
22
23
+ import javax .lang .model .element .TypeElement ;
24
+ import javax .lang .model .element .VariableElement ;
25
+ import javax .lang .model .type .TypeMirror ;
26
+ import javax .lang .model .util .ElementFilter ;
27
+
22
28
import org .junit .jupiter .api .Test ;
23
29
24
- import org .springframework .boot .configurationprocessor .TypeUtils .TypeDescriptor ;
25
30
import org .springframework .boot .configurationprocessor .test .RoundEnvironmentTester ;
26
31
import org .springframework .boot .configurationprocessor .test .TestableAnnotationProcessor ;
27
32
import org .springframework .boot .configurationsample .generic .AbstractGenericProperties ;
28
33
import org .springframework .boot .configurationsample .generic .AbstractIntermediateGenericProperties ;
34
+ import org .springframework .boot .configurationsample .generic .MixGenericNameProperties ;
29
35
import org .springframework .boot .configurationsample .generic .SimpleGenericProperties ;
36
+ import org .springframework .boot .configurationsample .generic .UnresolvedGenericProperties ;
30
37
import org .springframework .core .test .tools .SourceFile ;
31
38
import org .springframework .core .test .tools .TestCompiler ;
32
39
41
48
class TypeUtilsTests {
42
49
43
50
@ Test
44
- void resolveTypeDescriptorOnConcreteClass () {
51
+ void resolveTypeOnConcreteClass () {
45
52
process (SimpleGenericProperties .class , (roundEnv , typeUtils ) -> {
46
- TypeDescriptor typeDescriptor = typeUtils
47
- .resolveTypeDescriptor (roundEnv .getRootElement (SimpleGenericProperties .class ));
48
- assertThat (typeDescriptor .getGenerics ().keySet ().stream ().map (Object ::toString )).containsOnly ("A" , "B" ,
49
- "C" );
50
- assertThat (typeDescriptor .resolveGeneric ("A" )).hasToString (String .class .getName ());
51
- assertThat (typeDescriptor .resolveGeneric ("B" )).hasToString (Integer .class .getName ());
52
- assertThat (typeDescriptor .resolveGeneric ("C" )).hasToString (Duration .class .getName ());
53
-
53
+ TypeElement typeElement = roundEnv .getRootElement (SimpleGenericProperties .class );
54
+ assertThat (getTypeOfField (typeUtils , typeElement , "name" )).hasToString (String .class .getName ());
55
+ assertThat (getTypeOfField (typeUtils , typeElement , "mappings" ))
56
+ .hasToString (constructMapType (Integer .class , Duration .class ));
54
57
});
55
58
}
56
59
57
60
@ Test
58
- void resolveTypeDescriptorOnIntermediateClass () {
61
+ void resolveTypeOnIntermediateClass () {
59
62
process (AbstractIntermediateGenericProperties .class , (roundEnv , typeUtils ) -> {
60
- TypeDescriptor typeDescriptor = typeUtils
61
- .resolveTypeDescriptor (roundEnv .getRootElement (AbstractIntermediateGenericProperties .class ));
62
- assertThat (typeDescriptor .getGenerics ().keySet ().stream ().map (Object ::toString )).containsOnly ("A" , "B" ,
63
- "C" );
64
- assertThat (typeDescriptor .resolveGeneric ("A" )).hasToString (String .class .getName ());
65
- assertThat (typeDescriptor .resolveGeneric ("B" )).hasToString (Integer .class .getName ());
66
- assertThat (typeDescriptor .resolveGeneric ("C" )).hasToString ("C" );
63
+ TypeElement typeElement = roundEnv .getRootElement (AbstractIntermediateGenericProperties .class );
64
+ assertThat (getTypeOfField (typeUtils , typeElement , "name" )).hasToString (String .class .getName ());
65
+ assertThat (getTypeOfField (typeUtils , typeElement , "mappings" ))
66
+ .hasToString (constructMapType (Integer .class , Object .class ));
67
67
});
68
68
}
69
69
70
70
@ Test
71
- void resolveTypeDescriptorWithOnlyGenerics () {
71
+ void resolveTypeWithOnlyGenerics () {
72
72
process (AbstractGenericProperties .class , (roundEnv , typeUtils ) -> {
73
- TypeDescriptor typeDescriptor = typeUtils
74
- .resolveTypeDescriptor (roundEnv .getRootElement (AbstractGenericProperties .class ));
75
- assertThat (typeDescriptor .getGenerics ().keySet ().stream ().map (Object ::toString )).containsOnly ("A" , "B" ,
76
- "C" );
73
+ TypeElement typeElement = roundEnv .getRootElement (AbstractGenericProperties .class );
74
+ assertThat (getTypeOfField (typeUtils , typeElement , "name" )).hasToString (Object .class .getName ());
75
+ assertThat (getTypeOfField (typeUtils , typeElement , "mappings" ))
76
+ .hasToString (constructMapType (Object .class , Object .class ));
77
+ });
78
+ }
77
79
80
+ @ Test
81
+ void resolveTypeWithUnresolvedGenericProperties () {
82
+ process (UnresolvedGenericProperties .class , (roundEnv , typeUtils ) -> {
83
+ TypeElement typeElement = roundEnv .getRootElement (UnresolvedGenericProperties .class );
84
+ assertThat (getTypeOfField (typeUtils , typeElement , "name" )).hasToString (String .class .getName ());
85
+ assertThat (getTypeOfField (typeUtils , typeElement , "mappings" ))
86
+ .hasToString (constructMapType (Number .class , Object .class ));
87
+ });
88
+ }
89
+
90
+ @ Test
91
+ void resolvedTypeMixGenericNamePropertiesProperties () {
92
+ process (MixGenericNameProperties .class , (roundEnv , typeUtils ) -> {
93
+ TypeElement typeElement = roundEnv .getRootElement (MixGenericNameProperties .class );
94
+ assertThat (getTypeOfField (typeUtils , typeElement , "name" )).hasToString (String .class .getName ());
95
+ assertThat (getTypeOfField (typeUtils , typeElement , "mappings" ))
96
+ .hasToString (constructMapType (Number .class , Object .class ));
78
97
});
79
98
}
80
99
@@ -87,4 +106,29 @@ private void process(Class<?> target, BiConsumer<RoundEnvironmentTester, TypeUti
87
106
});
88
107
}
89
108
109
+ private String constructMapType (Class <?> keyType , Class <?> valueType ) {
110
+ return "%s<%s,%s>" .formatted (Map .class .getName (), keyType .getName (), valueType .getName ());
111
+ }
112
+
113
+ private String getTypeOfField (TypeUtils typeUtils , TypeElement typeElement , String name ) {
114
+ TypeMirror field = findField (typeUtils , typeElement , name );
115
+ if (field == null ) {
116
+ throw new IllegalStateException ("Unable to find field '" + name + "' in " + typeElement );
117
+ }
118
+ return typeUtils .getType (typeElement , field );
119
+ }
120
+
121
+ private TypeMirror findField (TypeUtils typeUtils , TypeElement typeElement , String name ) {
122
+ for (VariableElement variableElement : ElementFilter .fieldsIn (typeElement .getEnclosedElements ())) {
123
+ if (variableElement .getSimpleName ().contentEquals (name )) {
124
+ return variableElement .asType ();
125
+ }
126
+ }
127
+ TypeMirror superclass = typeElement .getSuperclass ();
128
+ if (superclass != null && !superclass .toString ().equals (Object .class .getName ())) {
129
+ return findField (typeUtils , (TypeElement ) typeUtils .asElement (superclass ), name );
130
+ }
131
+ return null ;
132
+ }
133
+
90
134
}
0 commit comments