1
+ package com .fasterxml .jackson .databind .introspect ;
2
+
3
+ import com .fasterxml .jackson .core .type .TypeReference ;
4
+ import com .fasterxml .jackson .databind .JavaType ;
5
+ import com .fasterxml .jackson .databind .type .TypeBindings ;
6
+ import com .fasterxml .jackson .databind .type .TypeFactory ;
7
+ import org .junit .Test ;
8
+
9
+ import java .lang .reflect .Method ;
10
+ import java .lang .reflect .Modifier ;
11
+ import java .lang .reflect .Type ;
12
+ import java .util .Collections ;
13
+ import java .util .HashMap ;
14
+ import java .util .List ;
15
+ import java .util .Map ;
16
+ import java .util .Optional ;
17
+
18
+ import static org .assertj .core .api .Assertions .assertThat ;
19
+
20
+ public class MethodGenericTypeResolverTest {
21
+
22
+ private static final TypeResolutionContext EMPTY_CONTEXT =
23
+ new TypeResolutionContext .Empty (TypeFactory .defaultInstance ());
24
+
25
+ public static <T > Optional <T > simple (T input ) {
26
+ throw new UnsupportedOperationException ();
27
+ }
28
+
29
+ public static Optional <?> noGenerics (String input ) {
30
+ throw new UnsupportedOperationException ();
31
+ }
32
+
33
+ public static <T > Map <T , T > mapWithSameKeysAndValues (List <T > input ) {
34
+ throw new UnsupportedOperationException ();
35
+ }
36
+
37
+ public static <T > Map <?, ?> disconnected (List <T > input ) {
38
+ throw new UnsupportedOperationException ();
39
+ }
40
+
41
+ public static <A , B > Map <A , B > multipleTypeVariables (Map <A , B > input ) {
42
+ throw new UnsupportedOperationException ();
43
+ }
44
+
45
+ public static <A , B > Map <? extends A , ? extends B > multipleTypeVariablesWithUpperBound (Map <A , B > input ) {
46
+ throw new UnsupportedOperationException ();
47
+ }
48
+
49
+ @ Test
50
+ public void testWithoutGenerics () {
51
+ TypeBindings bindings = MethodGenericTypeResolver .bindMethodTypeParameters (
52
+ method ("noGenerics" ), type (String .class ), EMPTY_CONTEXT );
53
+ assertThat (bindings ).isNull ();
54
+ }
55
+
56
+ @ Test
57
+ public void testWithoutGenericsInResult () {
58
+ TypeBindings bindings = MethodGenericTypeResolver .bindMethodTypeParameters (
59
+ method ("simple" ), type (Optional .class ), EMPTY_CONTEXT );
60
+ assertThat (bindings ).isNull ();
61
+ }
62
+
63
+ @ Test
64
+ public void testResultDoesNotUseTypeVariables () {
65
+ TypeBindings bindings = MethodGenericTypeResolver .bindMethodTypeParameters (
66
+ method ("disconnected" ), type (new TypeReference <Map <String , String >>() {
67
+ }), EMPTY_CONTEXT );
68
+ assertThat (bindings ).isNull ();
69
+ }
70
+
71
+ @ Test
72
+ public void testWithoutGenericsInMethod () {
73
+ TypeBindings bindings = MethodGenericTypeResolver .bindMethodTypeParameters (
74
+ method ("noGenerics" ), type (new TypeReference <Map <String , String >>() {
75
+ }), EMPTY_CONTEXT );
76
+ assertThat (bindings ).isNull ();
77
+ }
78
+
79
+ @ Test
80
+ public void testWithRepeatedGenericInReturn () {
81
+ TypeBindings bindings = MethodGenericTypeResolver .bindMethodTypeParameters (
82
+ method ("mapWithSameKeysAndValues" ), type (new TypeReference <Map <String , String >>() {
83
+ }), EMPTY_CONTEXT );
84
+ assertThat (asMap (bindings )).isEqualTo (asMap ("T" , type (String .class )));
85
+ }
86
+
87
+ @ Test
88
+ public void testMultipleTypeVariables () {
89
+ TypeBindings bindings = MethodGenericTypeResolver .bindMethodTypeParameters (
90
+ method ("multipleTypeVariables" ), type (new TypeReference <Map <Integer , Long >>() {
91
+ }), EMPTY_CONTEXT );
92
+ assertThat (asMap (bindings )).isEqualTo (asMap (
93
+ "A" , type (Integer .class ),
94
+ "B" , type (Long .class )));
95
+ }
96
+
97
+ @ Test
98
+ public void testMultipleTypeVariablesWithUpperBounds () {
99
+ TypeBindings bindings = MethodGenericTypeResolver .bindMethodTypeParameters (
100
+ method ("multipleTypeVariablesWithUpperBound" ), type (new TypeReference <Map <Integer , Long >>() {
101
+ }), EMPTY_CONTEXT );
102
+ assertThat (asMap (bindings )).isEqualTo (asMap (
103
+ "A" , type (Integer .class ),
104
+ "B" , type (Long .class )));
105
+ }
106
+
107
+ @ Test
108
+ public void testResultTypeDoesNotExactlyMatch () {
109
+ TypeBindings bindings = MethodGenericTypeResolver .bindMethodTypeParameters (
110
+ method ("multipleTypeVariables" ), type (new TypeReference <HashMap <Integer , Long >>() {
111
+ }), EMPTY_CONTEXT );
112
+ // Mapping the result to a common supertype is not supported.
113
+ assertThat (bindings ).isNull ();
114
+ }
115
+
116
+ private static Method method (String name ) {
117
+ Method result = null ;
118
+ for (Method method : MethodGenericTypeResolverTest .class .getMethods ()) {
119
+ if (Modifier .isStatic (method .getModifiers ()) && name .equals (method .getName ())) {
120
+ if (result != null ) {
121
+ throw new AssertionError ("Multiple methods discovered with name "
122
+ + name + ": " + result + " and " + method );
123
+ }
124
+ result = method ;
125
+ }
126
+ }
127
+ assertThat (result ).as ("Failed to find method named '%s'" , name ).isNotNull ();
128
+ return result ;
129
+ }
130
+
131
+ private static JavaType type (TypeReference <?> reference ) {
132
+ return type (reference .getType ());
133
+ }
134
+
135
+ private static JavaType type (Type type ) {
136
+ return EMPTY_CONTEXT .resolveType (type );
137
+ }
138
+
139
+ private static Map <String , JavaType > asMap (TypeBindings bindings ) {
140
+ assertThat (bindings ).isNotNull ();
141
+ Map <String , JavaType > result = new HashMap <>(bindings .size ());
142
+ for (int i = 0 ; i < bindings .size (); i ++) {
143
+ result .put (bindings .getBoundName (i ), bindings .getBoundType (i ));
144
+ }
145
+ assertThat (result ).hasSize (bindings .size ());
146
+ return result ;
147
+ }
148
+
149
+ private static Map <String , JavaType > asMap (String name , JavaType javaType ) {
150
+ return Collections .singletonMap (name , javaType );
151
+ }
152
+
153
+ private static Map <String , JavaType > asMap (
154
+ String name0 , JavaType javaType0 , String name1 , JavaType javaType1 ) {
155
+ Map <String , JavaType > result = new HashMap <>(2 );
156
+ result .put (name0 , javaType0 );
157
+ result .put (name1 , javaType1 );
158
+ return result ;
159
+ }
160
+ }
0 commit comments