19
19
import java .lang .reflect .AnnotatedElement ;
20
20
import java .lang .reflect .Method ;
21
21
import java .time .Duration ;
22
+ import java .util .ArrayList ;
22
23
import java .util .List ;
23
24
import java .util .Optional ;
25
+ import java .util .Set ;
24
26
import java .util .function .Function ;
25
27
import java .util .function .Supplier ;
26
28
46
48
import org .springframework .lang .Nullable ;
47
49
import org .springframework .util .Assert ;
48
50
import org .springframework .util .ClassUtils ;
51
+ import org .springframework .util .LinkedMultiValueMap ;
52
+ import org .springframework .util .MultiValueMap ;
49
53
import org .springframework .util .ObjectUtils ;
50
54
import org .springframework .util .StringUtils ;
51
55
import org .springframework .util .StringValueResolver ;
@@ -156,6 +160,7 @@ private void applyArguments(HttpRequestValues.Builder requestValues, Object[] ar
156
160
private record HttpRequestValuesInitializer (
157
161
@ Nullable HttpMethod httpMethod , @ Nullable String url ,
158
162
@ Nullable MediaType contentType , @ Nullable List <MediaType > acceptMediaTypes ,
163
+ @ Nullable MultiValueMap <String , String > otherHeaders ,
159
164
Supplier <HttpRequestValues .Builder > requestValuesSupplier ) {
160
165
161
166
public HttpRequestValues .Builder initializeRequestValuesBuilder () {
@@ -172,6 +177,16 @@ public HttpRequestValues.Builder initializeRequestValuesBuilder() {
172
177
if (this .acceptMediaTypes != null ) {
173
178
requestValues .setAccept (this .acceptMediaTypes );
174
179
}
180
+ if (this .otherHeaders != null ) {
181
+ this .otherHeaders .forEach ((name , values ) -> {
182
+ if (values .size () == 1 ) {
183
+ requestValues .addHeader (name , values .get (0 ));
184
+ }
185
+ else {
186
+ requestValues .addHeader (name , values .toArray (new String [0 ]));
187
+ }
188
+ });
189
+ }
175
190
return requestValues ;
176
191
}
177
192
@@ -202,9 +217,10 @@ public static HttpRequestValuesInitializer create(
202
217
String url = initUrl (typeAnnotation , methodAnnotation , embeddedValueResolver );
203
218
MediaType contentType = initContentType (typeAnnotation , methodAnnotation );
204
219
List <MediaType > acceptableMediaTypes = initAccept (typeAnnotation , methodAnnotation );
205
-
206
- return new HttpRequestValuesInitializer (
207
- httpMethod , url , contentType , acceptableMediaTypes , requestValuesSupplier );
220
+ MultiValueMap <String , String > headers = initHeaders (typeAnnotation , methodAnnotation ,
221
+ embeddedValueResolver );
222
+ return new HttpRequestValuesInitializer (httpMethod , url , contentType ,
223
+ acceptableMediaTypes , headers , requestValuesSupplier );
208
224
}
209
225
210
226
@ Nullable
@@ -280,6 +296,50 @@ private static List<MediaType> initAccept(@Nullable HttpExchange typeAnnotation,
280
296
return null ;
281
297
}
282
298
299
+ private static MultiValueMap <String , String > parseHeaders (String [] headersArray ,
300
+ @ Nullable StringValueResolver embeddedValueResolver ) {
301
+ MultiValueMap <String , String > headers = new LinkedMultiValueMap <>();
302
+ for (String h : headersArray ) {
303
+ String [] headerPair = StringUtils .split (h , "=" );
304
+ if (headerPair != null ) {
305
+ String headerName = headerPair [0 ].trim ();
306
+ List <String > headerValues = new ArrayList <>();
307
+ Set <String > parsedValues = StringUtils .commaDelimitedListToSet (headerPair [1 ]);
308
+ for (String headerValue : parsedValues ) {
309
+ if (embeddedValueResolver != null ) {
310
+ headerValue = embeddedValueResolver .resolveStringValue (headerValue );
311
+ }
312
+ if (headerValue != null ) {
313
+ headerValue = headerValue .trim ();
314
+ headerValues .add (headerValue );
315
+ }
316
+ }
317
+ if (!headerValues .isEmpty ()) {
318
+ headers .addAll (headerName , headerValues );
319
+ }
320
+ }
321
+ }
322
+ return headers ;
323
+ }
324
+
325
+ @ Nullable
326
+ private static MultiValueMap <String , String > initHeaders (@ Nullable HttpExchange typeAnnotation , HttpExchange methodAnnotation ,
327
+ @ Nullable StringValueResolver embeddedValueResolver ) {
328
+ MultiValueMap <String , String > methodLevelHeaders = parseHeaders (methodAnnotation .headers (),
329
+ embeddedValueResolver );
330
+ if (!ObjectUtils .isEmpty (methodLevelHeaders )) {
331
+ return methodLevelHeaders ;
332
+ }
333
+
334
+ MultiValueMap <String , String > typeLevelHeaders = (typeAnnotation != null ?
335
+ parseHeaders (typeAnnotation .headers (), embeddedValueResolver ) : null );
336
+ if (!ObjectUtils .isEmpty (typeLevelHeaders )) {
337
+ return typeLevelHeaders ;
338
+ }
339
+
340
+ return null ;
341
+ }
342
+
283
343
private static List <AnnotationDescriptor > getAnnotationDescriptors (AnnotatedElement element ) {
284
344
return MergedAnnotations .from (element , SearchStrategy .TYPE_HIERARCHY , RepeatableContainers .none ())
285
345
.stream (HttpExchange .class )
0 commit comments