Add HttpRequestValues.Processor
Closes gh-34699
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.web.service.invoker;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -176,6 +177,9 @@ public class HttpRequestValues {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a builder for {@link HttpRequestValues}.
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
@@ -209,6 +213,28 @@ public class HttpRequestValues {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A contract that allows further customization of {@link HttpRequestValues}
|
||||
* in addition to those added by argument resolvers.
|
||||
* <p>Use {@link HttpServiceProxyFactory.Builder#httpRequestValuesProcessor(Processor)}
|
||||
* to add such a processor.
|
||||
* @since 7.0
|
||||
*/
|
||||
public interface Processor {
|
||||
|
||||
/**
|
||||
* Invoked after argument resolvers have been called, and before the
|
||||
* {@link HttpRequestValues} is built.
|
||||
* @param method the {@code @HttpExchange} method
|
||||
* @param arguments the raw argument values to the method
|
||||
* @param builder the builder to add request values too; the builder
|
||||
* also exposes method {@link Metadata} from the {@code HttpExchange} method.
|
||||
*/
|
||||
void process(Method method, @Nullable Object[] arguments, Builder builder);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builder for {@link HttpRequestValues}.
|
||||
*/
|
||||
@@ -238,6 +264,9 @@ public class HttpRequestValues {
|
||||
|
||||
private @Nullable Object bodyValue;
|
||||
|
||||
protected Builder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the HTTP method for the request.
|
||||
*/
|
||||
|
||||
@@ -77,6 +77,8 @@ final class HttpServiceMethod {
|
||||
|
||||
private final List<HttpServiceArgumentResolver> argumentResolvers;
|
||||
|
||||
private final HttpRequestValues.Processor requestValuesProcessor;
|
||||
|
||||
private final HttpRequestValuesInitializer requestValuesInitializer;
|
||||
|
||||
private final ResponseFunction responseFunction;
|
||||
@@ -84,11 +86,13 @@ final class HttpServiceMethod {
|
||||
|
||||
HttpServiceMethod(
|
||||
Method method, Class<?> containingClass, List<HttpServiceArgumentResolver> argumentResolvers,
|
||||
HttpExchangeAdapter adapter, @Nullable StringValueResolver embeddedValueResolver) {
|
||||
HttpRequestValues.Processor valuesProcessor, HttpExchangeAdapter adapter,
|
||||
@Nullable StringValueResolver embeddedValueResolver) {
|
||||
|
||||
this.method = method;
|
||||
this.parameters = initMethodParameters(method);
|
||||
this.argumentResolvers = argumentResolvers;
|
||||
this.requestValuesProcessor = valuesProcessor;
|
||||
|
||||
boolean isReactorAdapter = (REACTOR_PRESENT && adapter instanceof ReactorHttpExchangeAdapter);
|
||||
|
||||
@@ -129,6 +133,7 @@ final class HttpServiceMethod {
|
||||
public @Nullable Object invoke(@Nullable Object[] arguments) {
|
||||
HttpRequestValues.Builder requestValues = this.requestValuesInitializer.initializeRequestValuesBuilder();
|
||||
applyArguments(requestValues, arguments);
|
||||
this.requestValuesProcessor.process(this.method, arguments, requestValues);
|
||||
return this.responseFunction.execute(requestValues.build());
|
||||
}
|
||||
|
||||
|
||||
@@ -58,15 +58,19 @@ public final class HttpServiceProxyFactory {
|
||||
|
||||
private final List<HttpServiceArgumentResolver> argumentResolvers;
|
||||
|
||||
private final HttpRequestValues.Processor requestValuesProcessor;
|
||||
|
||||
private final @Nullable StringValueResolver embeddedValueResolver;
|
||||
|
||||
|
||||
private HttpServiceProxyFactory(
|
||||
HttpExchangeAdapter exchangeAdapter, List<HttpServiceArgumentResolver> argumentResolvers,
|
||||
List<HttpRequestValues.Processor> requestValuesProcessor,
|
||||
@Nullable StringValueResolver embeddedValueResolver) {
|
||||
|
||||
this.exchangeAdapter = exchangeAdapter;
|
||||
this.argumentResolvers = argumentResolvers;
|
||||
this.requestValuesProcessor = new CompositeHttpRequestValuesProcessor(requestValuesProcessor);
|
||||
this.embeddedValueResolver = embeddedValueResolver;
|
||||
}
|
||||
|
||||
@@ -97,7 +101,8 @@ public final class HttpServiceProxyFactory {
|
||||
"No argument resolvers: afterPropertiesSet was not called");
|
||||
|
||||
return new HttpServiceMethod(
|
||||
method, serviceType, this.argumentResolvers, this.exchangeAdapter, this.embeddedValueResolver);
|
||||
method, serviceType, this.argumentResolvers, this.requestValuesProcessor,
|
||||
this.exchangeAdapter, this.embeddedValueResolver);
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +131,8 @@ public final class HttpServiceProxyFactory {
|
||||
|
||||
private final List<HttpServiceArgumentResolver> customArgumentResolvers = new ArrayList<>();
|
||||
|
||||
private final List<HttpRequestValues.Processor> requestValuesProcessors = new ArrayList<>();
|
||||
|
||||
private @Nullable ConversionService conversionService;
|
||||
|
||||
private @Nullable StringValueResolver embeddedValueResolver;
|
||||
@@ -154,6 +161,18 @@ public final class HttpServiceProxyFactory {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an {@link HttpRequestValues} processor that can further
|
||||
* customize request values based on the method and all arguments.
|
||||
* @param processor the processor to add
|
||||
* @return this same builder instance
|
||||
* @since 7.0
|
||||
*/
|
||||
public Builder httpRequestValuesProcessor(HttpRequestValues.Processor processor) {
|
||||
this.requestValuesProcessors.add(processor);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ConversionService} to use where input values need to
|
||||
* be formatted as Strings.
|
||||
@@ -183,7 +202,8 @@ public final class HttpServiceProxyFactory {
|
||||
Assert.notNull(this.exchangeAdapter, "HttpClientAdapter is required");
|
||||
|
||||
return new HttpServiceProxyFactory(
|
||||
this.exchangeAdapter, initArgumentResolvers(), this.embeddedValueResolver);
|
||||
this.exchangeAdapter, initArgumentResolvers(), this.requestValuesProcessors,
|
||||
this.embeddedValueResolver);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"DataFlowIssue", "NullAway"})
|
||||
@@ -251,7 +271,21 @@ public final class HttpServiceProxyFactory {
|
||||
System.arraycopy(args, 0, functionArgs, 0, args.length - 1);
|
||||
return functionArgs;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processor that delegates to a list of other processors.
|
||||
*/
|
||||
private record CompositeHttpRequestValuesProcessor(List<HttpRequestValues.Processor> processors)
|
||||
implements HttpRequestValues.Processor {
|
||||
|
||||
@Override
|
||||
public void process(Method method, @Nullable Object[] arguments, HttpRequestValues.Builder builder) {
|
||||
for (HttpRequestValues.Processor processor : this.processors) {
|
||||
processor.process(method, arguments, builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -94,6 +94,9 @@ public final class ReactiveHttpRequestValues extends HttpRequestValues {
|
||||
|
||||
private @Nullable ParameterizedTypeReference<?> bodyElementType;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setHttpMethod(HttpMethod httpMethod) {
|
||||
super.setHttpMethod(httpMethod);
|
||||
|
||||
@@ -198,12 +198,12 @@ class HttpServiceMethodTests {
|
||||
|
||||
@Test
|
||||
void typeAndMethodAnnotatedService() {
|
||||
HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builder()
|
||||
.exchangeAdapter(this.client)
|
||||
.embeddedValueResolver(value -> (value.equals("${baseUrl}") ? "/base" : value))
|
||||
.build();
|
||||
|
||||
MethodLevelAnnotatedService service = proxyFactory.createClient(TypeAndMethodLevelAnnotatedService.class);
|
||||
MethodLevelAnnotatedService service = HttpServiceProxyFactory.builder()
|
||||
.exchangeAdapter(this.client)
|
||||
.embeddedValueResolver(value -> (value.equals("${baseUrl}") ? "/base" : value))
|
||||
.build()
|
||||
.createClient(TypeAndMethodLevelAnnotatedService.class);
|
||||
|
||||
service.performGet();
|
||||
|
||||
@@ -222,6 +222,19 @@ class HttpServiceMethodTests {
|
||||
assertThat(requestValues.getHeaders().getAccept()).containsOnly(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
@Test
|
||||
void httpRequestValuesProcessor() {
|
||||
|
||||
HttpServiceProxyFactory.builder()
|
||||
.exchangeAdapter(this.client)
|
||||
.httpRequestValuesProcessor((m, a, builder) -> builder.addAttribute("foo", "a"))
|
||||
.build()
|
||||
.createClient(Service.class)
|
||||
.execute();
|
||||
|
||||
assertThat(this.client.getRequestValues().getAttributes().get("foo")).isEqualTo("a");
|
||||
}
|
||||
|
||||
@Test // gh-32049
|
||||
void multipleAnnotationsAtClassLevel() {
|
||||
Class<?> serviceInterface = MultipleClassLevelAnnotationsService.class;
|
||||
|
||||
Reference in New Issue
Block a user