Reject multiple @HttpExchange declarations in HTTP interface clients
This commit updates HttpServiceMethod so that multiple @HttpExchange declarations on the same element (class or method) are rejected. Closes gh-32049
This commit is contained in:
@@ -16,6 +16,11 @@
|
||||
|
||||
package org.springframework.web.service.invoker;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -37,8 +42,10 @@ import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.service.annotation.GetExchange;
|
||||
import org.springframework.web.service.annotation.HttpExchange;
|
||||
import org.springframework.web.service.annotation.PostExchange;
|
||||
import org.springframework.web.service.annotation.PutExchange;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.springframework.http.MediaType.APPLICATION_CBOR_VALUE;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
|
||||
@@ -52,6 +59,7 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
class HttpServiceMethodTests {
|
||||
|
||||
@@ -204,6 +212,33 @@ class HttpServiceMethodTests {
|
||||
assertThat(requestValues.getHeaders().getAccept()).containsExactly(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
@Test // gh-32049
|
||||
void multipleAnnotationsAtClassLevel() {
|
||||
Class<?> serviceInterface = MultipleClassLevelAnnotationsService.class;
|
||||
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> this.proxyFactory.createClient(serviceInterface))
|
||||
.withMessageContainingAll(
|
||||
"Multiple @HttpExchange annotations found on " + serviceInterface,
|
||||
"@" + HttpExchange.class.getName(),
|
||||
"@" + ExtraHttpExchange.class.getName()
|
||||
);
|
||||
}
|
||||
|
||||
@Test // gh-32049
|
||||
void multipleAnnotationsAtMethodLevel() throws NoSuchMethodException {
|
||||
Class<?> serviceInterface = MultipleMethodLevelAnnotationsService.class;
|
||||
Method method = serviceInterface.getMethod("post");
|
||||
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> this.proxyFactory.createClient(serviceInterface))
|
||||
.withMessageContainingAll(
|
||||
"Multiple @HttpExchange annotations found on method " + method,
|
||||
"@" + PostExchange.class.getName(),
|
||||
"@" + PutExchange.class.getName()
|
||||
);
|
||||
}
|
||||
|
||||
protected void verifyReactorClientInvocation(String methodName, @Nullable ParameterizedTypeReference<?> expectedBodyType) {
|
||||
assertThat(this.reactorClient.getInvokedMethodName()).isEqualTo(methodName);
|
||||
assertThat(this.reactorClient.getBodyType()).isEqualTo(expectedBodyType);
|
||||
@@ -305,9 +340,34 @@ class HttpServiceMethodTests {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@HttpExchange(url = "${baseUrl}", contentType = APPLICATION_CBOR_VALUE, accept = APPLICATION_CBOR_VALUE)
|
||||
private interface TypeAndMethodLevelAnnotatedService extends MethodLevelAnnotatedService {
|
||||
}
|
||||
|
||||
|
||||
@HttpExchange("/exchange")
|
||||
@ExtraHttpExchange
|
||||
private interface MultipleClassLevelAnnotationsService {
|
||||
|
||||
@PostExchange("/post")
|
||||
void post();
|
||||
}
|
||||
|
||||
|
||||
private interface MultipleMethodLevelAnnotationsService {
|
||||
|
||||
@PostExchange("/post")
|
||||
@PutExchange("/post")
|
||||
void post();
|
||||
}
|
||||
|
||||
|
||||
@HttpExchange
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private @interface ExtraHttpExchange {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user