1 package org.bremersee.apiclient.webflux.contract.spring;
2
3 import static java.util.Objects.nonNull;
4
5 import java.lang.reflect.Method;
6 import java.util.Optional;
7 import java.util.function.Function;
8 import org.bremersee.apiclient.webflux.Invocation;
9 import org.bremersee.apiclient.webflux.InvocationParameter;
10 import org.springframework.core.ResolvableType;
11 import org.springframework.http.MediaType;
12 import org.springframework.util.MultiValueMap;
13 import org.springframework.web.reactive.function.BodyInserters;
14 import org.springframework.web.reactive.function.client.WebClient.RequestBodyUriSpec;
15 import org.springframework.web.reactive.function.client.WebClient.RequestHeadersUriSpec;
16
17
18
19
20
21
22 public class FormDataInserter extends SingleBodyInserter<MultiValueMap<String, ?>> {
23
24 private Function<Invocation, Optional<MediaType>> contentTypeResolver = new ContentTypeResolver();
25
26
27
28
29
30
31
32 public FormDataInserter withContentTypeResolver(
33 Function<Invocation, Optional<MediaType>> contentTypeResolver) {
34
35 if (nonNull(contentTypeResolver)) {
36 this.contentTypeResolver = contentTypeResolver;
37 }
38 return this;
39 }
40
41 @Override
42 public boolean canInsert(Invocation invocation) {
43 return isFormData(invocation) && super.canInsert(invocation);
44 }
45
46
47
48
49
50
51
52 protected boolean isFormData(Invocation invocation) {
53 return contentTypeResolver.apply(invocation)
54 .filter(contentType -> contentType.isCompatibleWith(MediaType.APPLICATION_FORM_URLENCODED))
55 .isPresent();
56 }
57
58 @Override
59 protected MultiValueMap<String, ?> mapBody(InvocationParameter invocationParameter) {
60
61 return (MultiValueMap<String, ?>) invocationParameter.getValue();
62 }
63
64 @Override
65 protected boolean isPossibleBodyValue(InvocationParameter invocationParameter) {
66 return invocationParameter.getValue() instanceof MultiValueMap && isString(invocationParameter);
67 }
68
69 private boolean isString(InvocationParameter invocationParameter) {
70 Method method = invocationParameter.getMethod();
71 int index = invocationParameter.getIndex();
72 return Optional.of(ResolvableType.forMethodParameter(method, index))
73 .filter(resolvableType -> resolvableType.getGenerics().length >= 2)
74 .map(resolvableType -> resolvableType.resolveGeneric(0))
75 .filter(String.class::isAssignableFrom)
76 .isPresent();
77 }
78
79 @Override
80 protected RequestHeadersUriSpec<?> insert(
81 MultiValueMap<String, ?> body,
82 RequestBodyUriSpec requestBodyUriSpec) {
83
84
85 return (RequestHeadersUriSpec) requestBodyUriSpec
86 .body(BodyInserters.fromFormData((MultiValueMap<String, String>) body));
87 }
88
89 }