Add HttpMethod and PathVariable argument resolvers
See gh-28386
This commit is contained in:
parent
c418768f05
commit
c2a008fc22
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.service.invoker;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* An implementation of {@link HttpServiceMethodArgumentResolver} that resolves
|
||||
* request HTTP method based on argument type. Arguments of type
|
||||
* {@link HttpMethod} will be used to determine the method.
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 6.0
|
||||
*/
|
||||
public class HttpMethodArgumentResolver implements HttpServiceMethodArgumentResolver {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(HttpMethodArgumentResolver.class);
|
||||
|
||||
@Override
|
||||
public void resolve(@Nullable Object argument, MethodParameter parameter,
|
||||
HttpRequestDefinition requestDefinition) {
|
||||
if (argument == null) {
|
||||
return;
|
||||
}
|
||||
if (argument instanceof HttpMethod httpMethod) {
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Resolved HTTP method to: " + httpMethod.name());
|
||||
}
|
||||
requestDefinition.setHttpMethod(httpMethod);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,7 +28,9 @@ import org.reactivestreams.Publisher;
|
|||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.ReactiveAdapter;
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
|
@ -104,6 +106,8 @@ final class HttpServiceMethod {
|
|||
Assert.isTrue(arguments.length == this.parameters.length, "Method argument mismatch");
|
||||
for (int i = 0; i < this.parameters.length; i++) {
|
||||
Object argumentValue = arguments[i];
|
||||
ParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
|
||||
this.parameters[i].initParameterNameDiscovery(nameDiscoverer);
|
||||
for (HttpServiceMethodArgumentResolver resolver : this.argumentResolvers) {
|
||||
resolver.resolve(argumentValue, this.parameters[i], requestDefinition);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.springframework.web.service.invoker;
|
||||
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.service.invoker;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ReactiveAdapter;
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
||||
/**
|
||||
* An implementation of {@link HttpServiceMethodArgumentResolver} that resolves
|
||||
* request path variables based on method arguments annotated
|
||||
* with {@link PathVariable}. {@code null} values are allowed only
|
||||
* if {@link PathVariable#required()} is {@code true}.
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 6.0
|
||||
*/
|
||||
public class PathVariableArgumentResolver implements HttpServiceMethodArgumentResolver {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(PathVariableArgumentResolver.class);
|
||||
private static final TypeDescriptor STRING_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class);
|
||||
@Nullable
|
||||
private final ConversionService conversionService;
|
||||
|
||||
public PathVariableArgumentResolver(@Nullable ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolve(@Nullable Object argument, MethodParameter parameter,
|
||||
HttpRequestDefinition requestDefinition) {
|
||||
PathVariable annotation = parameter.getParameterAnnotation(PathVariable.class);
|
||||
if (annotation == null) {
|
||||
return;
|
||||
}
|
||||
String resolvedAnnotationName = StringUtils.hasText(annotation.value())
|
||||
? annotation.value() : annotation.name();
|
||||
boolean required = annotation.required();
|
||||
Object resolvedArgument = resolveFromOptional(argument);
|
||||
if (resolvedArgument instanceof Map<?, ?> valueMap) {
|
||||
if (StringUtils.hasText(resolvedAnnotationName)) {
|
||||
Object value = valueMap.get(resolvedAnnotationName);
|
||||
Object resolvedValue = resolveFromOptional(value);
|
||||
addUriParameter(requestDefinition, resolvedAnnotationName, resolvedValue, required);
|
||||
return;
|
||||
}
|
||||
valueMap.entrySet()
|
||||
.forEach(entry -> addUriParameter(requestDefinition, entry, required));
|
||||
return;
|
||||
}
|
||||
String name = StringUtils.hasText(resolvedAnnotationName)
|
||||
? resolvedAnnotationName : parameter.getParameterName();
|
||||
addUriParameter(requestDefinition, name, resolvedArgument, required);
|
||||
}
|
||||
|
||||
private void addUriParameter(HttpRequestDefinition requestDefinition, @Nullable String name,
|
||||
@Nullable Object value, boolean required) {
|
||||
if (name == null) {
|
||||
throw new IllegalStateException("Path variable name cannot be null");
|
||||
}
|
||||
String stringValue = getStringValue(value, required);
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Path variable " + name + " resolved to " + stringValue);
|
||||
}
|
||||
requestDefinition.getUriVariables().put(name, stringValue);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getStringValue(@Nullable Object value, boolean required) {
|
||||
validateForNull(value, required);
|
||||
validateForReactiveWrapper(value);
|
||||
return value != null
|
||||
? convertToString(TypeDescriptor.valueOf(value.getClass()), value) : null;
|
||||
}
|
||||
|
||||
private void addUriParameter(HttpRequestDefinition requestDefinition,
|
||||
Map.Entry<?, ?> entry, boolean required) {
|
||||
Object resolvedName = resolveFromOptional(entry.getKey());
|
||||
String stringName = getStringValue(resolvedName, true);
|
||||
Object resolvedValue = resolveFromOptional(entry.getValue());
|
||||
addUriParameter(requestDefinition, stringName, resolvedValue, required);
|
||||
}
|
||||
|
||||
private void validateForNull(@Nullable Object argument, boolean required) {
|
||||
if (argument == null) {
|
||||
if (required) {
|
||||
throw new IllegalStateException("Required variable cannot be null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateForReactiveWrapper(@Nullable Object object) {
|
||||
if (object != null) {
|
||||
Class<?> type = object.getClass();
|
||||
ReactiveAdapterRegistry adapterRegistry = ReactiveAdapterRegistry.getSharedInstance();
|
||||
ReactiveAdapter adapter = adapterRegistry.getAdapter(type);
|
||||
if (adapter != null) {
|
||||
throw new IllegalStateException(getClass().getSimpleName() +
|
||||
" does not support reactive type wrapper: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object resolveFromOptional(@Nullable Object argument) {
|
||||
if (argument instanceof Optional) {
|
||||
return ((Optional<?>) argument).orElse(null);
|
||||
}
|
||||
return argument;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String convertToString(TypeDescriptor typeDescriptor, @Nullable Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return (String) value;
|
||||
}
|
||||
if (this.conversionService != null) {
|
||||
return (String) this.conversionService.convert(value, typeDescriptor, STRING_TYPE_DESCRIPTOR);
|
||||
}
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.service.invoker;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.service.annotation.GetRequest;
|
||||
import org.springframework.web.service.annotation.HttpRequest;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link HttpMethodArgumentResolver}.
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
class HttpMethodArgumentResolverTests extends HttpServiceMethodTestSupport {
|
||||
|
||||
private final Service service = createService(Service.class,
|
||||
Collections.singletonList(new HttpMethodArgumentResolver()));
|
||||
|
||||
@Test
|
||||
void shouldResolveRequestMethodFromArgument() {
|
||||
Mono<Void> execution = this.service.execute(HttpMethod.GET);
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldIgnoreArgumentsNotMatchingType() {
|
||||
Mono<Void> execution = this.service.execute("test");
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getHttpMethod()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldOverrideMethodAnnotationWithMethodArgument() {
|
||||
Mono<Void> execution = this.service.executeGet(HttpMethod.POST);
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldIgnoreNullValue() {
|
||||
Mono<Void> execution = this.service.executeForNull(null);
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getHttpMethod()).isNull();
|
||||
}
|
||||
|
||||
|
||||
private interface Service {
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> execute(HttpMethod method);
|
||||
|
||||
@GetRequest
|
||||
Mono<Void> executeGet(HttpMethod method);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> execute(String test);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> execute(HttpMethod firstMethod, HttpMethod secondMethod);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeForNull(@Nullable HttpMethod method);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.service.invoker;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Contains utility methods for {@link HttpServiceMethod} tests.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
public class HttpServiceMethodTestSupport {
|
||||
|
||||
private final TestHttpClientAdapter clientAdapter;
|
||||
|
||||
protected HttpServiceMethodTestSupport() {
|
||||
clientAdapter = new TestHttpClientAdapter();
|
||||
}
|
||||
|
||||
protected <S> S createService(Class<S> serviceType) {
|
||||
return createService(serviceType, Collections.emptyList());
|
||||
}
|
||||
|
||||
protected <S> S createService(Class<S> serviceType,
|
||||
List<HttpServiceMethodArgumentResolver> argumentResolvers) {
|
||||
HttpServiceProxyFactory factory = new HttpServiceProxyFactory(
|
||||
argumentResolvers, this.clientAdapter, ReactiveAdapterRegistry.getSharedInstance(),
|
||||
Duration.ofSeconds(5));
|
||||
|
||||
return factory.createService(serviceType);
|
||||
}
|
||||
|
||||
protected HttpRequestDefinition getRequestDefinition() {
|
||||
return this.clientAdapter.getRequestDefinition();
|
||||
}
|
||||
|
||||
|
||||
protected TestHttpClientAdapter getClientAdapter() {
|
||||
return this.clientAdapter;
|
||||
}
|
||||
|
||||
protected static class TestHttpClientAdapter implements HttpClientAdapter {
|
||||
|
||||
@Nullable
|
||||
private String methodName;
|
||||
|
||||
@Nullable
|
||||
private HttpRequestDefinition requestDefinition;
|
||||
|
||||
@Nullable
|
||||
private ParameterizedTypeReference<?> bodyType;
|
||||
|
||||
|
||||
String getMethodName() {
|
||||
assertThat(this.methodName).isNotNull();
|
||||
return this.methodName;
|
||||
}
|
||||
|
||||
HttpRequestDefinition getRequestDefinition() {
|
||||
assertThat(this.requestDefinition).isNotNull();
|
||||
return this.requestDefinition;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ParameterizedTypeReference<?> getBodyType() {
|
||||
return this.bodyType;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Mono<Void> requestToVoid(HttpRequestDefinition def) {
|
||||
saveInput("requestToVoid", def, null);
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<HttpHeaders> requestToHeaders(HttpRequestDefinition def) {
|
||||
saveInput("requestToHeaders", def, null);
|
||||
return Mono.just(new HttpHeaders());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<T> requestToBody(HttpRequestDefinition def,
|
||||
ParameterizedTypeReference<T> bodyType) {
|
||||
saveInput("requestToBody", def, bodyType);
|
||||
return (Mono<T>) Mono.just(getMethodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Flux<T> requestToBodyFlux(HttpRequestDefinition def,
|
||||
ParameterizedTypeReference<T> bodyType) {
|
||||
saveInput("requestToBodyFlux", def, bodyType);
|
||||
return (Flux<T>) Flux.just("request", "To", "Body", "Flux");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ResponseEntity<Void>> requestToBodilessEntity(HttpRequestDefinition def) {
|
||||
saveInput("requestToBodilessEntity", def, null);
|
||||
return Mono.just(ResponseEntity.ok().build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<ResponseEntity<T>> requestToEntity(HttpRequestDefinition def,
|
||||
ParameterizedTypeReference<T> bodyType) {
|
||||
saveInput("requestToEntity", def, bodyType);
|
||||
return Mono.just((ResponseEntity<T>) ResponseEntity.ok("requestToEntity"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<ResponseEntity<Flux<T>>> requestToEntityFlux(HttpRequestDefinition def,
|
||||
ParameterizedTypeReference<T> bodyType) {
|
||||
saveInput("requestToEntityFlux", def, bodyType);
|
||||
return Mono.just(ResponseEntity.ok((Flux<T>) Flux.just("request", "To", "Entity", "Flux")));
|
||||
}
|
||||
|
||||
private <T> void saveInput(
|
||||
String methodName, HttpRequestDefinition definition,
|
||||
@Nullable ParameterizedTypeReference<T> bodyType) {
|
||||
|
||||
this.methodName = methodName;
|
||||
this.requestDefinition = definition;
|
||||
this.bodyType = bodyType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -17,9 +17,6 @@
|
|||
package org.springframework.web.service.invoker;
|
||||
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
|
||||
import io.reactivex.rxjava3.core.Completable;
|
||||
import io.reactivex.rxjava3.core.Flowable;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
@ -29,7 +26,6 @@ import reactor.core.publisher.Mono;
|
|||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
@ -55,19 +51,14 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
|||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class HttpServiceMethodTests {
|
||||
public class HttpServiceMethodTests extends HttpServiceMethodTestSupport {
|
||||
|
||||
private static final ParameterizedTypeReference<String> BODY_TYPE = new ParameterizedTypeReference<>() {};
|
||||
|
||||
|
||||
private final TestHttpClientAdapter clientAdapter = new TestHttpClientAdapter();
|
||||
|
||||
|
||||
@Test
|
||||
void reactorService() {
|
||||
|
||||
ReactorService service = createService(ReactorService.class);
|
||||
|
||||
|
||||
Mono<Void> voidMono = service.execute();
|
||||
StepVerifier.create(voidMono).verifyComplete();
|
||||
verifyClientInvocation("requestToVoid", null);
|
||||
|
@ -99,9 +90,7 @@ public class HttpServiceMethodTests {
|
|||
|
||||
@Test
|
||||
void rxJavaService() {
|
||||
|
||||
RxJavaService service = createService(RxJavaService.class);
|
||||
|
||||
Completable completable = service.execute();
|
||||
assertThat(completable).isNotNull();
|
||||
|
||||
|
@ -152,7 +141,7 @@ public class HttpServiceMethodTests {
|
|||
|
||||
service.performGet();
|
||||
|
||||
HttpRequestDefinition request = this.clientAdapter.getRequestDefinition();
|
||||
HttpRequestDefinition request = getRequestDefinition();
|
||||
assertThat(request.getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(request.getUriTemplate()).isNull();
|
||||
assertThat(request.getHeaders().getContentType()).isNull();
|
||||
|
@ -160,7 +149,7 @@ public class HttpServiceMethodTests {
|
|||
|
||||
service.performPost();
|
||||
|
||||
request = this.clientAdapter.getRequestDefinition();
|
||||
request = getRequestDefinition();
|
||||
assertThat(request.getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(request.getUriTemplate()).isEqualTo("/url");
|
||||
assertThat(request.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
|
||||
|
@ -174,7 +163,7 @@ public class HttpServiceMethodTests {
|
|||
|
||||
service.performGet();
|
||||
|
||||
HttpRequestDefinition request = this.clientAdapter.getRequestDefinition();
|
||||
HttpRequestDefinition request = getRequestDefinition();
|
||||
assertThat(request.getHttpMethod()).isEqualTo(HttpMethod.GET);
|
||||
assertThat(request.getUriTemplate()).isEqualTo("/base");
|
||||
assertThat(request.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_CBOR);
|
||||
|
@ -182,25 +171,17 @@ public class HttpServiceMethodTests {
|
|||
|
||||
service.performPost();
|
||||
|
||||
request = this.clientAdapter.getRequestDefinition();
|
||||
request = getRequestDefinition();
|
||||
assertThat(request.getHttpMethod()).isEqualTo(HttpMethod.POST);
|
||||
assertThat(request.getUriTemplate()).isEqualTo("/base/url");
|
||||
assertThat(request.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
|
||||
assertThat(request.getHeaders().getAccept()).containsExactly(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
private <S> S createService(Class<S> serviceType) {
|
||||
|
||||
HttpServiceProxyFactory factory = new HttpServiceProxyFactory(
|
||||
Collections.emptyList(), this.clientAdapter, ReactiveAdapterRegistry.getSharedInstance(),
|
||||
Duration.ofSeconds(5));
|
||||
|
||||
return factory.createService(serviceType);
|
||||
}
|
||||
|
||||
private void verifyClientInvocation(String methodName, @Nullable ParameterizedTypeReference<?> expectedBodyType) {
|
||||
assertThat((this.clientAdapter.getMethodName())).isEqualTo(methodName);
|
||||
assertThat(this.clientAdapter.getBodyType()).isEqualTo(expectedBodyType);
|
||||
TestHttpClientAdapter clientAdapter = getClientAdapter();
|
||||
assertThat((clientAdapter.getMethodName())).isEqualTo(methodName);
|
||||
assertThat(clientAdapter.getBodyType()).isEqualTo(expectedBodyType);
|
||||
}
|
||||
|
||||
|
||||
|
@ -292,87 +273,4 @@ public class HttpServiceMethodTests {
|
|||
@HttpRequest(url = "/base", contentType = APPLICATION_CBOR_VALUE, accept = APPLICATION_CBOR_VALUE)
|
||||
private interface TypeAndMethodAnnotatedService extends MethodAnnotatedService {
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static class TestHttpClientAdapter implements HttpClientAdapter {
|
||||
|
||||
@Nullable
|
||||
private String methodName;
|
||||
|
||||
@Nullable
|
||||
private HttpRequestDefinition requestDefinition;
|
||||
|
||||
@Nullable
|
||||
private ParameterizedTypeReference<?> bodyType;
|
||||
|
||||
|
||||
public String getMethodName() {
|
||||
assertThat(this.methodName).isNotNull();
|
||||
return this.methodName;
|
||||
}
|
||||
|
||||
public HttpRequestDefinition getRequestDefinition() {
|
||||
assertThat(this.requestDefinition).isNotNull();
|
||||
return this.requestDefinition;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ParameterizedTypeReference<?> getBodyType() {
|
||||
return this.bodyType;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Mono<Void> requestToVoid(HttpRequestDefinition def) {
|
||||
saveInput("requestToVoid", def, null);
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<HttpHeaders> requestToHeaders(HttpRequestDefinition def) {
|
||||
saveInput("requestToHeaders", def, null);
|
||||
return Mono.just(new HttpHeaders());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<T> requestToBody(HttpRequestDefinition def, ParameterizedTypeReference<T> bodyType) {
|
||||
saveInput("requestToBody", def, bodyType);
|
||||
return (Mono<T>) Mono.just(getMethodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Flux<T> requestToBodyFlux(HttpRequestDefinition def, ParameterizedTypeReference<T> bodyType) {
|
||||
saveInput("requestToBodyFlux", def, bodyType);
|
||||
return (Flux<T>) Flux.just("request", "To", "Body", "Flux");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ResponseEntity<Void>> requestToBodilessEntity(HttpRequestDefinition def) {
|
||||
saveInput("requestToBodilessEntity", def, null);
|
||||
return Mono.just(ResponseEntity.ok().build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<ResponseEntity<T>> requestToEntity(HttpRequestDefinition def, ParameterizedTypeReference<T> bodyType) {
|
||||
saveInput("requestToEntity", def, bodyType);
|
||||
return Mono.just((ResponseEntity<T>) ResponseEntity.ok("requestToEntity"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<ResponseEntity<Flux<T>>> requestToEntityFlux(HttpRequestDefinition def, ParameterizedTypeReference<T> bodyType) {
|
||||
saveInput("requestToEntityFlux", def, bodyType);
|
||||
return Mono.just(ResponseEntity.ok((Flux<T>) Flux.just("request", "To", "Entity", "Flux")));
|
||||
}
|
||||
|
||||
private <T> void saveInput(
|
||||
String methodName, HttpRequestDefinition definition, @Nullable ParameterizedTypeReference<T> bodyType) {
|
||||
|
||||
this.methodName = methodName;
|
||||
this.requestDefinition = definition;
|
||||
this.bodyType = bodyType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,515 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.service.invoker;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import io.reactivex.rxjava3.core.Observable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.service.annotation.HttpRequest;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link PathVariableArgumentResolver}.
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
class PathVariableArgumentResolverTests extends HttpServiceMethodTestSupport {
|
||||
|
||||
private final Service service = createService(Service.class,
|
||||
Collections.singletonList(new PathVariableArgumentResolver(null)));
|
||||
|
||||
@Test
|
||||
void shouldResolvePathVariableWithNameFromParameter() {
|
||||
Mono<Void> execution = this.service.execute("test");
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolvePathVariableWithNameFromAnnotationName() {
|
||||
Mono<Void> execution = this.service.executeNamed("test");
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolvePathVariableNameFromValue() {
|
||||
Mono<Void> execution = this.service.executeNamedWithValue("test");
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldOverrideNameIfValuePresentInAnnotation() {
|
||||
Mono<Void> execution = this.service.executeValueNamed("test");
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolvePathVariableWithNameFromObject() {
|
||||
Mono<Void> execution = this.service.execute(new TestObject("test"));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolvePathVariableWithConversionService() {
|
||||
Service service = createService(Service.class,
|
||||
Collections.singletonList(new PathVariableArgumentResolver(
|
||||
new DefaultConversionService())));
|
||||
Mono<Void> execution = service.execute(Boolean.TRUE);
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo("true");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolvePathVariableFromOptionalArgumentWithConversionService() {
|
||||
Service service = createService(Service.class,
|
||||
Collections.singletonList(new PathVariableArgumentResolver(
|
||||
new DefaultConversionService())));
|
||||
Mono<Void> execution = service.executeOptional(Optional.of(Boolean.TRUE));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo("true");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolvePathVariableFromOptionalArgument() {
|
||||
Mono<Void> execution = this.service.execute(Optional.of("test"));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForNullWithConversionService() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Service service = createService(Service.class,
|
||||
Collections.singletonList(new PathVariableArgumentResolver(
|
||||
new DefaultConversionService())));
|
||||
Mono<Void> execution = service.executeNamedWithValue(null);
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForNull() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Mono<Void> execution = this.service.executeNamedWithValue(null);
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForEmptyOptional() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Service service = createService(Service.class, Collections.singletonList(new PathVariableArgumentResolver(new DefaultConversionService())));
|
||||
Mono<Void> execution = service.execute(Optional.empty());
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForEmptyOptionalWithoutConversionService() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Mono<Void> execution = this.service.execute(Optional.empty());
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotThrowExceptionForNullWithConversionServiceWhenNotRequired() {
|
||||
Service service = createService(Service.class, Collections.singletonList(new PathVariableArgumentResolver(new DefaultConversionService())));
|
||||
Mono<Void> execution = service.executeNotRequired(null);
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotThrowExceptionForNullWhenNotRequired() {
|
||||
Mono<Void> execution = this.service.executeNotRequired(null);
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotThrowExceptionForEmptyOptionalWhenNotRequired() {
|
||||
Service service = createService(Service.class, Collections.singletonList(new PathVariableArgumentResolver(new DefaultConversionService())));
|
||||
Mono<Void> execution = service.executeOptionalNotRequired(Optional.empty());
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotThrowExceptionForEmptyOptionalWithoutConversionServiceWhenNotRequired() {
|
||||
Mono<Void> execution = this.service.executeOptionalNotRequired(Optional.empty());
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForReactorWrapper() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Mono<Void> execution = this.service.executeMono(Mono.just("test"));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForRXWrapper() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Mono<Void> execution = this.service.executeObservable(Observable.just("test"));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForOptionalReactorWrapper() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Mono<Void> execution = this.service.executeOptionalMono(Optional.of(Mono.just("test")));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForOptionalRXWrapper() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Mono<Void> execution = this.service.executeOptionalObservable(Optional.of(Observable.just("test")));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolvePathVariableFromNamedMap() {
|
||||
Mono<Void> execution = this.service.executeNamedMap(Map.of("id", "test"));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolvePathVariableFromMapWithAnnotationValue() {
|
||||
Mono<Void> execution = this.service.executeNamedValueMap(Map.of("id", "test"));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForReactorWrapperInNamedMap() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Mono<Void> execution = this.service.executeNamedReactorMap(Map.of("id", Flux.just("test")));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolveOptionalPathVariableFromNamedMap() {
|
||||
Mono<Void> execution = this.service.executeOptionalValueNamedMap(Map.of("id", Optional.of("test")));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolveNamedPathVariableFromNamedMapWithConversionService() {
|
||||
Service service = createService(Service.class, Collections.singletonList(new PathVariableArgumentResolver(new DefaultConversionService())));
|
||||
Mono<Void> execution = service.executeNamedBooleanMap(Map.of("id", Boolean.TRUE));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo("true");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForNullNamedMap() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Mono<Void> execution = this.service.executeNamedValueMap(null);
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForNullNamedMapValue() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Mono<Void> execution = this.service.executeNamedValueMap(new HashMap<>());
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForEmptyOptionalNamedMapValue() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Service service = createService(Service.class, Collections.singletonList(new PathVariableArgumentResolver(new DefaultConversionService())));
|
||||
Mono<Void> execution = service.executeOptionalValueNamedMap(Map.of("id", Optional.empty()));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotThrowExceptionForNullNamedMapValueWhenNotRequired() {
|
||||
Mono<Void> execution = this.service.executeNamedValueMapNotRequired(null);
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotThrowExceptionForEmptyOptionalNamedMapValueWhenNotRequired() {
|
||||
Service service = createService(Service.class, Collections.singletonList(new PathVariableArgumentResolver(new DefaultConversionService())));
|
||||
Mono<Void> execution = service.executeOptionalValueMapNotRequired(Map.of("id", Optional.empty()));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolvePathVariablesFromMap() {
|
||||
Mono<Void> execution = this.service.executeValueMap(Map.of("id", "test"));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForReactorWrapperValueInMap() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Mono<Void> execution = this.service.executeReactorValueMap(Map.of("id", Flux.just("test")));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForReactorWrapperKeyInMap() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Mono<Void> execution = this.service.executeReactorKeyMap(Map.of(Flux.just("id"), "test"));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolvePathVariableFromOptionalMapValue() {
|
||||
Mono<Void> execution = this.service.executeOptionalValueMap(Map.of("id", Optional.of("test")));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolvePathVariableFromOptionalMapKey() {
|
||||
Mono<Void> execution = this.service.executeOptionalKeyMap(Map.of(Optional.of("id"), "test"));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolvePathVariableFromMapWithConversionService() {
|
||||
Service service = createService(Service.class, Collections.singletonList(new PathVariableArgumentResolver(new DefaultConversionService())));
|
||||
Mono<Void> execution = service.executeBooleanMap(Map.of(Boolean.TRUE, Boolean.TRUE));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables()
|
||||
.get("true")).isEqualTo("true");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForNullMapValue() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Mono<Void> execution = this.service.executeValueMap(null);
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForEmptyOptionalMapValue() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Service service = createService(Service.class, Collections.singletonList(new PathVariableArgumentResolver(new DefaultConversionService())));
|
||||
Mono<Void> execution = service.executeOptionalValueMap(Map.of("id", Optional.empty()));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionForEmptyOptionalMapKey() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
Service service = createService(Service.class, Collections.singletonList(new PathVariableArgumentResolver(new DefaultConversionService())));
|
||||
Mono<Void> execution = service.executeOptionalKeyMap(Map.of(Optional.empty(), "test"));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotThrowExceptionForNullMapValueWhenNotRequired() {
|
||||
Mono<Void> execution = this.service.executeValueMapNotRequired(null);
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotThrowExceptionForEmptyOptionalMapValueWhenNotRequired() {
|
||||
Service service = createService(Service.class, Collections.singletonList(new PathVariableArgumentResolver(new DefaultConversionService())));
|
||||
Mono<Void> execution = service.executeOptionalValueMapNotRequired(Map.of("id", Optional.empty()));
|
||||
|
||||
StepVerifier.create(execution).verifyComplete();
|
||||
assertThat(getRequestDefinition().getUriVariables().get("id")).isEqualTo(null);
|
||||
}
|
||||
|
||||
|
||||
private interface Service {
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> execute(@PathVariable String id);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeNotRequired(@Nullable @PathVariable(required = false) String id);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeOptional(@PathVariable Optional<Boolean> id);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeOptionalNotRequired(@PathVariable(required = false) Optional<String> id);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeNamedWithValue(@Nullable @PathVariable(name = "test", value = "id") String employeeId);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeNamed(@PathVariable(name = "id") String employeeId);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeValueNamed(@PathVariable("id") String employeeId);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> execute(@PathVariable Object id);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> execute(@PathVariable Boolean id);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeMono(@PathVariable Mono<String> id);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeObservable(@PathVariable Observable<String> id);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeOptionalMono(@PathVariable Optional<Mono<String>> id);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeOptionalObservable(@PathVariable Optional<Observable<String>> id);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeNamedMap(@PathVariable(name = "id") Map<String, String> map);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeNamedValueMap(@Nullable @PathVariable("id") Map<String, String> map);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeNamedBooleanMap(@PathVariable("id") Map<String, Boolean> map);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeNamedReactorMap(@PathVariable(name = "id") Map<String, Flux<String>> map);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeOptionalValueNamedMap(@PathVariable("id") Map<String, Optional<String>> map);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeNamedValueMapNotRequired(@Nullable @PathVariable(name = "id", required = false) Map<String, String> map);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeOptionalValueMapNotRequired(@PathVariable(name = "id", required = false) Map<String, Optional<String>> map);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeValueMap(@Nullable @PathVariable Map<String, String> map);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeReactorValueMap(@PathVariable Map<String, Flux<String>> map);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeReactorKeyMap(@PathVariable Map<Flux<String>, String> map);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeOptionalValueMap(@PathVariable Map<String, Optional<String>> map);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeOptionalKeyMap(@PathVariable Map<Optional<String>, String> map);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeBooleanMap(@PathVariable Map<Boolean, Boolean> map);
|
||||
|
||||
@HttpRequest
|
||||
Mono<Void> executeValueMapNotRequired(@Nullable @PathVariable(required = false) Map<String, String> map);
|
||||
}
|
||||
|
||||
static class TestObject {
|
||||
|
||||
TestObject(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
String value;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue