Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,19 @@ public final class HttpServiceProxyFactory {

private final @Nullable StringValueResolver embeddedValueResolver;

private final List<ProxyFactoryCustomizer> proxyCustomizers;

private HttpServiceProxyFactory(
HttpExchangeAdapter exchangeAdapter, List<HttpServiceArgumentResolver> argumentResolvers,
List<HttpRequestValues.Processor> requestValuesProcessor,
@Nullable StringValueResolver embeddedValueResolver) {
@Nullable StringValueResolver embeddedValueResolver,
List<ProxyFactoryCustomizer> proxyCustomizers) {

this.exchangeAdapter = exchangeAdapter;
this.argumentResolvers = argumentResolvers;
this.requestValuesProcessor = new CompositeHttpRequestValuesProcessor(requestValuesProcessor);
this.embeddedValueResolver = embeddedValueResolver;
this.proxyCustomizers = proxyCustomizers;
}


Expand All @@ -84,7 +87,6 @@ private HttpServiceProxyFactory(
* @return the created proxy
*/
public <S> S createClient(Class<S> serviceType) {

List<HttpServiceMethod> httpServiceMethods =
MethodIntrospector.selectMethods(serviceType, this::isExchangeMethod).stream()
.map(method -> createHttpServiceMethod(serviceType, method))
Expand All @@ -97,6 +99,9 @@ public <S> S createClient(Class<S> serviceType) {
private <S> S getProxy(Class<S> serviceType, List<HttpServiceMethod> httpServiceMethods) {
MethodInterceptor interceptor = new HttpServiceMethodInterceptor(httpServiceMethods);
ProxyFactory factory = new ProxyFactory(serviceType, interceptor);
for (var customizer : this.proxyCustomizers) {
customizer.customize(factory, serviceType);
}
return (S) factory.getProxy(serviceType.getClassLoader());
}

Expand Down Expand Up @@ -147,6 +152,8 @@ public static final class Builder {

private @Nullable StringValueResolver embeddedValueResolver;

private final List<ProxyFactoryCustomizer> proxyCustomizers = new ArrayList<>();

private Builder() {
}

Expand Down Expand Up @@ -216,6 +223,19 @@ public Builder embeddedValueResolver(StringValueResolver embeddedValueResolver)
return this;
}

/**
* Register an {@link ProxyFactoryCustomizer} that can
* manipulating the {@link ProxyFactory} before creating proxy.
*
* @param customizer the customizer to add
* @return this same builder instance
* @since 7.1
*/
public Builder proxyCustomizer(ProxyFactoryCustomizer customizer) {
this.proxyCustomizers.add(customizer);
return this;
}

/**
* Build the {@link HttpServiceProxyFactory} instance.
*/
Expand All @@ -225,7 +245,7 @@ public HttpServiceProxyFactory build() {

return new HttpServiceProxyFactory(
adapterToUse, initArgumentResolvers(), this.requestValuesProcessors,
this.embeddedValueResolver);
this.embeddedValueResolver, this.proxyCustomizers);
}

@SuppressWarnings({"DataFlowIssue", "NullAway"})
Expand Down Expand Up @@ -313,4 +333,18 @@ public void process(
}
}

/**
* Callback interface used during HttpService proxy creation. Allows manipulating the {@link ProxyFactory} creating the
* HttpService.
*
* @author Dung Dang Minh
*/
public interface ProxyFactoryCustomizer {
/**
* Manipulates the {@link ProxyFactory}, e.g. add further interceptors to it.
*
* @param factory will never be {@literal null}.
*/
void customize(ProxyFactory factory, Class<?> serviceType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@

package org.springframework.web.service.invoker;

import org.aopalliance.intercept.MethodInterceptor;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;

import org.springframework.core.ParameterizedTypeReference;
import org.springframework.web.service.annotation.GetExchange;

Expand All @@ -44,6 +44,18 @@ void httpExchangeAdapterDecorator() {
}


@Test
void proxyFactoryCustomizer() {
var mi = (MethodInterceptor) invocation -> "intercepted";
var factory = HttpServiceProxyFactory.builderFor(mock(HttpExchangeAdapter.class))
.proxyCustomizer((fact, serviceType) -> {
fact.addAdvice(0, mi);
}).build();

var service = factory.createClient(Service.class);
assertThat(service.execute()).isEqualTo("intercepted");
}

private interface Service {

@GetExchange
Expand Down