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
+ 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 ));
53
57
54
58
});
55
59
}
56
60
57
61
@ Test
58
- void resolveTypeDescriptorOnIntermediateClass () {
62
+ void resolveTypeOnIntermediateClass () {
59
63
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" );
64
+ TypeElement typeElement = roundEnv .getRootElement (AbstractIntermediateGenericProperties .class );
65
+ assertThat (getTypeOfField (typeUtils , typeElement , "name" )).hasToString (String .class .getName ());
66
+ assertThat (getTypeOfField (typeUtils , typeElement , "mappings" ))
67
+ .hasToString (constructMapType (Integer .class , Object .class ));
67
68
});
68
69
}
69
70
70
71
@ Test
71
- void resolveTypeDescriptorWithOnlyGenerics () {
72
+ void resolveTypeWithOnlyGenerics () {
72
73
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" );
74
+ TypeElement typeElement = roundEnv .getRootElement (AbstractGenericProperties .class );
75
+ assertThat (getTypeOfField (typeUtils , typeElement , "name" )).hasToString (Object .class .getName ());
76
+ assertThat (getTypeOfField (typeUtils , typeElement , "mappings" ))
77
+ .hasToString (constructMapType (Object .class , Object .class ));
78
+ });
79
+ }
80
+
81
+ @ Test
82
+ void resolveTypeWithUnresolvedGenericProperties () {
83
+ process (UnresolvedGenericProperties .class , (roundEnv , typeUtils ) -> {
84
+ TypeElement typeElement = roundEnv .getRootElement (UnresolvedGenericProperties .class );
85
+ assertThat (getTypeOfField (typeUtils , typeElement , "name" )).hasToString (String .class .getName ());
86
+ assertThat (getTypeOfField (typeUtils , typeElement , "mappings" ))
87
+ .hasToString (constructMapType (Number .class , Object .class ));
88
+ });
89
+ }
77
90
91
+ @ Test
92
+ void resolvedTypeMixGenericNamePropertiesProperties () {
93
+ process (MixGenericNameProperties .class , (roundEnv , typeUtils ) -> {
94
+ TypeElement typeElement = roundEnv .getRootElement (MixGenericNameProperties .class );
95
+ assertThat (getTypeOfField (typeUtils , typeElement , "name" )).hasToString (String .class .getName ());
96
+ assertThat (getTypeOfField (typeUtils , typeElement , "mappings" ))
97
+ .hasToString (constructMapType (Number .class , Object .class ));
78
98
});
79
99
}
80
100
@@ -87,4 +107,29 @@ private void process(Class<?> target, BiConsumer<RoundEnvironmentTester, TypeUti
87
107
});
88
108
}
89
109
110
+ private String constructMapType (Class <?> keyType , Class <?> valueType ) {
111
+ return "%s<%s,%s>" .formatted (Map .class .getName (), keyType .getName (), valueType .getName ());
112
+ }
113
+
114
+ private String getTypeOfField (TypeUtils typeUtils , TypeElement typeElement , String name ) {
115
+ TypeMirror field = findField (typeUtils , typeElement , name );
116
+ if (field == null ) {
117
+ throw new IllegalStateException ("Unable to find field '" + name + "' in " + typeElement );
118
+ }
119
+ return typeUtils .getType (typeElement , field );
120
+ }
121
+
122
+ private TypeMirror findField (TypeUtils typeUtils , TypeElement typeElement , String name ) {
123
+ for (VariableElement variableElement : ElementFilter .fieldsIn (typeElement .getEnclosedElements ())) {
124
+ if (variableElement .getSimpleName ().contentEquals (name )) {
125
+ return variableElement .asType ();
126
+ }
127
+ }
128
+ TypeMirror superclass = typeElement .getSuperclass ();
129
+ if (superclass != null && !superclass .toString ().equals (Object .class .getName ())) {
130
+ return findField (typeUtils , (TypeElement ) typeUtils .asElement (superclass ), name );
131
+ }
132
+ return null ;
133
+ }
134
+
90
135
}
0 commit comments