parent
ce568468ae
commit
2a2fba6a37
|
|
@ -42,6 +42,7 @@ import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.util.StringValueResolver;
|
||||||
import org.springframework.web.service.annotation.HttpExchange;
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -67,13 +68,13 @@ final class HttpServiceMethod {
|
||||||
|
|
||||||
HttpServiceMethod(
|
HttpServiceMethod(
|
||||||
Method method, Class<?> containingClass, List<HttpServiceArgumentResolver> argumentResolvers,
|
Method method, Class<?> containingClass, List<HttpServiceArgumentResolver> argumentResolvers,
|
||||||
HttpClientAdapter client, ReactiveAdapterRegistry reactiveRegistry,
|
HttpClientAdapter client, @Nullable StringValueResolver embeddedValueResolver,
|
||||||
Duration blockTimeout) {
|
ReactiveAdapterRegistry reactiveRegistry, Duration blockTimeout) {
|
||||||
|
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.parameters = initMethodParameters(method);
|
this.parameters = initMethodParameters(method);
|
||||||
this.argumentResolvers = argumentResolvers;
|
this.argumentResolvers = argumentResolvers;
|
||||||
this.requestValuesInitializer = HttpRequestValuesInitializer.create(method, containingClass);
|
this.requestValuesInitializer = HttpRequestValuesInitializer.create(method, containingClass, embeddedValueResolver);
|
||||||
this.responseFunction = ResponseFunction.create(client, method, reactiveRegistry, blockTimeout);
|
this.responseFunction = ResponseFunction.create(client, method, reactiveRegistry, blockTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,7 +162,8 @@ final class HttpServiceMethod {
|
||||||
/**
|
/**
|
||||||
* Introspect the method and create the request factory for it.
|
* Introspect the method and create the request factory for it.
|
||||||
*/
|
*/
|
||||||
public static HttpRequestValuesInitializer create(Method method, Class<?> containingClass) {
|
public static HttpRequestValuesInitializer create(
|
||||||
|
Method method, Class<?> containingClass, @Nullable StringValueResolver embeddedValueResolver) {
|
||||||
|
|
||||||
HttpExchange annot1 = AnnotatedElementUtils.findMergedAnnotation(containingClass, HttpExchange.class);
|
HttpExchange annot1 = AnnotatedElementUtils.findMergedAnnotation(containingClass, HttpExchange.class);
|
||||||
HttpExchange annot2 = AnnotatedElementUtils.findMergedAnnotation(method, HttpExchange.class);
|
HttpExchange annot2 = AnnotatedElementUtils.findMergedAnnotation(method, HttpExchange.class);
|
||||||
|
|
@ -169,7 +171,7 @@ final class HttpServiceMethod {
|
||||||
Assert.notNull(annot2, "Expected HttpRequest annotation");
|
Assert.notNull(annot2, "Expected HttpRequest annotation");
|
||||||
|
|
||||||
HttpMethod httpMethod = initHttpMethod(annot1, annot2);
|
HttpMethod httpMethod = initHttpMethod(annot1, annot2);
|
||||||
String url = initUrl(annot1, annot2);
|
String url = initUrl(annot1, annot2, embeddedValueResolver);
|
||||||
MediaType contentType = initContentType(annot1, annot2);
|
MediaType contentType = initContentType(annot1, annot2);
|
||||||
List<MediaType> acceptableMediaTypes = initAccept(annot1, annot2);
|
List<MediaType> acceptableMediaTypes = initAccept(annot1, annot2);
|
||||||
|
|
||||||
|
|
@ -194,11 +196,17 @@ final class HttpServiceMethod {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static String initUrl(@Nullable HttpExchange typeAnnot, HttpExchange annot) {
|
private static String initUrl(
|
||||||
|
@Nullable HttpExchange typeAnnot, HttpExchange annot, @Nullable StringValueResolver embeddedValueResolver) {
|
||||||
|
|
||||||
String url1 = (typeAnnot != null ? typeAnnot.url() : null);
|
String url1 = (typeAnnot != null ? typeAnnot.url() : null);
|
||||||
String url2 = annot.url();
|
String url2 = annot.url();
|
||||||
|
|
||||||
|
if (embeddedValueResolver != null) {
|
||||||
|
url1 = (url1 != null ? embeddedValueResolver.resolveStringValue(url1) : null);
|
||||||
|
url2 = embeddedValueResolver.resolveStringValue(url2);
|
||||||
|
}
|
||||||
|
|
||||||
boolean hasUrl1 = StringUtils.hasText(url1);
|
boolean hasUrl1 = StringUtils.hasText(url1);
|
||||||
boolean hasUrl2 = StringUtils.hasText(url2);
|
boolean hasUrl2 = StringUtils.hasText(url2);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ import org.springframework.core.convert.ConversionService;
|
||||||
import org.springframework.format.support.DefaultFormattingConversionService;
|
import org.springframework.format.support.DefaultFormattingConversionService;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.StringValueResolver;
|
||||||
import org.springframework.web.service.annotation.HttpExchange;
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -50,6 +51,9 @@ public final class HttpServiceProxyFactory {
|
||||||
|
|
||||||
private final List<HttpServiceArgumentResolver> argumentResolvers;
|
private final List<HttpServiceArgumentResolver> argumentResolvers;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final StringValueResolver embeddedValueResolver;
|
||||||
|
|
||||||
private final ReactiveAdapterRegistry reactiveAdapterRegistry;
|
private final ReactiveAdapterRegistry reactiveAdapterRegistry;
|
||||||
|
|
||||||
private final Duration blockTimeout;
|
private final Duration blockTimeout;
|
||||||
|
|
@ -57,10 +61,12 @@ public final class HttpServiceProxyFactory {
|
||||||
|
|
||||||
private HttpServiceProxyFactory(
|
private HttpServiceProxyFactory(
|
||||||
HttpClientAdapter clientAdapter, List<HttpServiceArgumentResolver> argumentResolvers,
|
HttpClientAdapter clientAdapter, List<HttpServiceArgumentResolver> argumentResolvers,
|
||||||
ReactiveAdapterRegistry reactiveAdapterRegistry, Duration blockTimeout) {
|
@Nullable StringValueResolver embeddedValueResolver, ReactiveAdapterRegistry reactiveAdapterRegistry,
|
||||||
|
Duration blockTimeout) {
|
||||||
|
|
||||||
this.clientAdapter = clientAdapter;
|
this.clientAdapter = clientAdapter;
|
||||||
this.argumentResolvers = argumentResolvers;
|
this.argumentResolvers = argumentResolvers;
|
||||||
|
this.embeddedValueResolver = embeddedValueResolver;
|
||||||
this.reactiveAdapterRegistry = reactiveAdapterRegistry;
|
this.reactiveAdapterRegistry = reactiveAdapterRegistry;
|
||||||
this.blockTimeout = blockTimeout;
|
this.blockTimeout = blockTimeout;
|
||||||
}
|
}
|
||||||
|
|
@ -80,8 +86,8 @@ public final class HttpServiceProxyFactory {
|
||||||
.stream()
|
.stream()
|
||||||
.map(method ->
|
.map(method ->
|
||||||
new HttpServiceMethod(
|
new HttpServiceMethod(
|
||||||
method, serviceType, this.argumentResolvers,
|
method, serviceType, this.argumentResolvers, this.clientAdapter,
|
||||||
this.clientAdapter, this.reactiveAdapterRegistry, this.blockTimeout))
|
this.embeddedValueResolver, this.reactiveAdapterRegistry, this.blockTimeout))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
return ProxyFactory.getProxy(serviceType, new HttpServiceMethodInterceptor(methods));
|
return ProxyFactory.getProxy(serviceType, new HttpServiceMethodInterceptor(methods));
|
||||||
|
|
@ -114,6 +120,9 @@ public final class HttpServiceProxyFactory {
|
||||||
@Nullable
|
@Nullable
|
||||||
private ConversionService conversionService;
|
private ConversionService conversionService;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private StringValueResolver embeddedValueResolver;
|
||||||
|
|
||||||
private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance();
|
private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance();
|
||||||
|
|
||||||
private Duration blockTimeout = Duration.ofSeconds(5);
|
private Duration blockTimeout = Duration.ofSeconds(5);
|
||||||
|
|
@ -144,6 +153,18 @@ public final class HttpServiceProxyFactory {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the StringValueResolver to use for resolving placeholders and
|
||||||
|
* expressions in {@link HttpExchange#url()}.
|
||||||
|
* @param embeddedValueResolver the resolver to use
|
||||||
|
* @return the same builder instance
|
||||||
|
* @see org.springframework.context.EmbeddedValueResolverAware
|
||||||
|
*/
|
||||||
|
public Builder setEmbeddedValueResolver(@Nullable StringValueResolver embeddedValueResolver) {
|
||||||
|
this.embeddedValueResolver = embeddedValueResolver;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the {@link ReactiveAdapterRegistry} to use to support different
|
* Set the {@link ReactiveAdapterRegistry} to use to support different
|
||||||
* asynchronous types for HTTP service method return values.
|
* asynchronous types for HTTP service method return values.
|
||||||
|
|
@ -176,7 +197,8 @@ public final class HttpServiceProxyFactory {
|
||||||
List<HttpServiceArgumentResolver> resolvers = initArgumentResolvers(conversionService);
|
List<HttpServiceArgumentResolver> resolvers = initArgumentResolvers(conversionService);
|
||||||
|
|
||||||
return new HttpServiceProxyFactory(
|
return new HttpServiceProxyFactory(
|
||||||
this.clientAdapter, resolvers, this.reactiveAdapterRegistry, this.blockTimeout);
|
this.clientAdapter, resolvers, this.embeddedValueResolver, this.reactiveAdapterRegistry,
|
||||||
|
this.blockTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConversionService initConversionService() {
|
private ConversionService initConversionService() {
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,11 @@ public class HttpServiceMethodTests {
|
||||||
@Test
|
@Test
|
||||||
void typeAndMethodAnnotatedService() {
|
void typeAndMethodAnnotatedService() {
|
||||||
|
|
||||||
MethodLevelAnnotatedService service = this.proxyFactory.createClient(TypeAndMethodLevelAnnotatedService.class);
|
HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builder(this.clientAdapter)
|
||||||
|
.setEmbeddedValueResolver(value -> (value.equals("${baseUrl}") ? "/base" : value))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
MethodLevelAnnotatedService service = proxyFactory.createClient(TypeAndMethodLevelAnnotatedService.class);
|
||||||
|
|
||||||
service.performGet();
|
service.performGet();
|
||||||
|
|
||||||
|
|
@ -281,7 +285,7 @@ public class HttpServiceMethodTests {
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@HttpExchange(url = "/base", contentType = APPLICATION_CBOR_VALUE, accept = APPLICATION_CBOR_VALUE)
|
@HttpExchange(url = "${baseUrl}", contentType = APPLICATION_CBOR_VALUE, accept = APPLICATION_CBOR_VALUE)
|
||||||
private interface TypeAndMethodLevelAnnotatedService extends MethodLevelAnnotatedService {
|
private interface TypeAndMethodLevelAnnotatedService extends MethodLevelAnnotatedService {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue