6
6
package io .leangen .geantyref ;
7
7
8
8
import java .lang .annotation .Annotation ;
9
- import java .lang .reflect .AnnotatedArrayType ;
10
- import java .lang .reflect .AnnotatedParameterizedType ;
11
- import java .lang .reflect .AnnotatedType ;
12
- import java .lang .reflect .AnnotatedTypeVariable ;
13
- import java .lang .reflect .AnnotatedWildcardType ;
14
- import java .lang .reflect .ParameterizedType ;
15
- import java .lang .reflect .Type ;
16
- import java .lang .reflect .TypeVariable ;
17
- import java .lang .reflect .WildcardType ;
9
+ import java .lang .reflect .*;
18
10
import java .util .Arrays ;
19
11
import java .util .HashMap ;
20
12
import java .util .Map ;
21
13
22
- import static io .leangen .geantyref .GenericTypeReflector .*;
14
+ import static io .leangen .geantyref .GenericTypeReflector .annotate ;
15
+ import static io .leangen .geantyref .GenericTypeReflector .merge ;
16
+ import static io .leangen .geantyref .GenericTypeReflector .updateAnnotations ;
23
17
import static java .util .Arrays .stream ;
24
18
25
19
/**
28
22
* @author Wouter Coekaerts {@literal (wouter@coekaerts.be)}
29
23
* @author Bojan Tomic {@literal (veggen@gmail.com)}
30
24
*/
25
+ @ SuppressWarnings ("rawtypes" )
31
26
class VarMap {
32
27
33
28
private final Map <TypeVariable , AnnotatedType > map = new HashMap <>();
29
+ private final Map <AnnotatedTypeVariable , AnnotatedTypeVariable > varCache = new HashMap <>();
34
30
35
31
/**
36
32
* Creates an empty VarMap
@@ -51,7 +47,8 @@ class VarMap {
51
47
52
48
// since we're looping over two arrays in parallel, just to be sure check they have the same size
53
49
if (arguments .length != typeParameters .length ) {
54
- throw new IllegalStateException ("The given type [" + type + "] is inconsistent: it has " +
50
+ throw new IllegalStateException (
51
+ "The given type [" + type + "] is inconsistent: it has " +
55
52
arguments .length + " arguments instead of " + typeParameters .length );
56
53
}
57
54
@@ -94,15 +91,21 @@ AnnotatedType map(AnnotatedType type, MappingMode mappingMode) {
94
91
TypeVariable <?> tv = (TypeVariable ) type .getType ();
95
92
if (!map .containsKey (tv )) {
96
93
if (mappingMode .equals (MappingMode .ALLOW_INCOMPLETE )) {
97
- AnnotatedTypeVariable variable = (AnnotatedTypeVariable ) type ;
98
- AnnotatedType [] bounds = map (variable .getAnnotatedBounds (), mappingMode );
94
+ AnnotatedTypeVariable variable = cloneVar ((AnnotatedTypeVariable ) type );
95
+
96
+ if (varCache .containsKey (variable )) {
97
+ return varCache .get (variable );
98
+ }
99
99
Annotation [] merged = merge (variable .getAnnotations (), tv .getAnnotations ());
100
- TypeVariableImpl v = new TypeVariableImpl <>(tv , merged , bounds );
101
- return new AnnotatedTypeVariableImpl (v , merged );
100
+ AnnotatedTypeVariableImpl v = new AnnotatedTypeVariableImpl (tv , merged );
101
+ varCache .put (variable , v );
102
+ AnnotatedType [] bounds = map (variable .getAnnotatedBounds (), mappingMode );
103
+ return v .init (bounds );
102
104
} else {
103
105
throw new UnresolvedTypeVariableException (tv );
104
106
}
105
107
}
108
+ //#IMPLTNOTE1 Flip key.equals(tv), as the equality check will fail if the underlying variable is replaced
106
109
TypeVariable varFromClass = map .keySet ().stream ().filter (key -> key .equals (tv )).findFirst ().get ();
107
110
Annotation [] merged = merge (type .getAnnotations (), tv .getAnnotations (), map .get (tv ).getAnnotations (), varFromClass .getAnnotations ());
108
111
return updateAnnotations (map .get (tv ), merged );
@@ -116,8 +119,8 @@ AnnotatedType map(AnnotatedType type, MappingMode mappingMode) {
116
119
typeParameters [i ] = updateAnnotations (typeParameter , raw .getTypeParameters ()[i ].getAnnotations ());
117
120
}
118
121
Type [] rawArgs = stream (typeParameters ).map (AnnotatedType ::getType ).toArray (Type []::new );
119
- Type innerOwnerType = inner .getOwnerType () == null ? null : map (annotate (inner .getOwnerType ()), mappingMode ).getType ();
120
- ParameterizedType newInner = new ParameterizedTypeImpl ((Class ) inner .getRawType (), rawArgs , innerOwnerType );
122
+ Type innerOwnerType = inner .getOwnerType () == null ? null : map (annotate (inner .getOwnerType ()), mappingMode ).getType ();
123
+ ParameterizedType newInner = new ParameterizedTypeImpl ((Class ) inner .getRawType (), rawArgs , innerOwnerType );
121
124
return new AnnotatedParameterizedTypeImpl (newInner , merge (pType .getAnnotations (), raw .getAnnotations ()), typeParameters );
122
125
} else if (type instanceof AnnotatedWildcardType ) {
123
126
AnnotatedWildcardType wType = (AnnotatedWildcardType ) type ;
@@ -139,7 +142,7 @@ AnnotatedType map(AnnotatedType type, MappingMode mappingMode) {
139
142
}
140
143
141
144
AnnotatedType [] map (AnnotatedType [] types ) {
142
- return map (types , MappingMode .EXACT );
145
+ return map (types , MappingMode .EXACT );
143
146
}
144
147
145
148
AnnotatedType [] map (AnnotatedType [] types , MappingMode mappingMode ) {
@@ -162,4 +165,11 @@ Type map(Type type) {
162
165
public enum MappingMode {
163
166
EXACT , ALLOW_INCOMPLETE
164
167
}
168
+
169
+ AnnotatedTypeVariable cloneVar (AnnotatedTypeVariable v ) {
170
+ if (v instanceof AnnotatedTypeVariableImpl ) {
171
+ return v ;
172
+ }
173
+ return new AnnotatedTypeVariableImpl ((TypeVariable <?>) v .getType (), v .getAnnotations ());
174
+ }
165
175
}
0 commit comments