8 changed files with 979 additions and 112 deletions
@ -0,0 +1,51 @@
@@ -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); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,152 @@
@@ -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 @@
@@ -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 @@
@@ -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; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,515 @@
@@ -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