Add CollectionFormat support (#371)

* Add CollectionFormat support. Fixes gh-146.

* Minor refactoring.

* Fix docs.
This commit is contained in:
Olga Maciaszek-Sharma
2020-07-17 08:05:21 -05:00
committed by GitHub
parent 4e89dd1523
commit d3da7e16e8
5 changed files with 227 additions and 55 deletions

View File

@@ -586,6 +586,25 @@ public interface DemoTemplate {
}
----
=== Feign `CollectionFormat` support
We support `feign.CollectionFormat` by providing the `@CollectionFormat` annotation. You can annotate a Feign client method with it by passing the desired `feign.CollectionFormat` as annotation value.
In the following example, the `CSV` format is used instead of the default `EXPLODED` to process the method.
[source,java,indent=0]
----
@FeignClient(name = "demo")
protected interface PageableFeignClient {
@CollectionFormat(feign.CollectionFormat.CSV)
@GetMapping(path = "/page")
ResponseEntity performRequest(Pageable page);
}
----
TIP: Set the `CSV` format while sending `Pageable` as a query parameter in order for it to be encoded correctly.
=== Reactive Support
As the https://github.com/OpenFeign/feign[OpenFeign project] does not currently support reactive clients, such as https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/function/client/WebClient.html[Spring WebClient], neither does Spring Cloud OpenFeign. We will add support for it here as soon as it becomes available in the core project.

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2013-2020 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.cloud.openfeign;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Indicates which collection format should be used while processing the annotated method.
*
* @author Olga Maciaszek-Sharma
* @see feign.CollectionFormat
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CollectionFormat {
/**
* Allows setting the {@link feign.CollectionFormat} to be used while processing the
* annotated method.
* @return the {@link feign.CollectionFormat} to be used
*/
feign.CollectionFormat value();
}

View File

@@ -37,6 +37,7 @@ import feign.Param;
import feign.Request;
import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;
import org.springframework.cloud.openfeign.CollectionFormat;
import org.springframework.cloud.openfeign.annotation.MatrixVariableParameterProcessor;
import org.springframework.cloud.openfeign.annotation.PathVariableParameterProcessor;
import org.springframework.cloud.openfeign.annotation.QueryMapParameterProcessor;
@@ -121,9 +122,9 @@ public class SpringMvcContract extends Contract.BaseContract
List<AnnotatedParameterProcessor> processors = getDefaultAnnotatedArgumentsProcessors();
processors.addAll(annotatedParameterProcessors);
this.annotatedArgumentProcessors = toAnnotatedArgumentProcessorMap(processors);
annotatedArgumentProcessors = toAnnotatedArgumentProcessorMap(processors);
this.conversionService = conversionService;
this.convertingExpanderFactory = new ConvertingExpanderFactory(conversionService);
convertingExpanderFactory = new ConvertingExpanderFactory(conversionService);
}
private static TypeDescriptor createTypeDescriptor(Method method, int paramIndex) {
@@ -187,7 +188,7 @@ public class SpringMvcContract extends Contract.BaseContract
@Override
public MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
this.processedMethods.put(Feign.configKey(targetType, method), method);
processedMethods.put(Feign.configKey(targetType, method), method);
MethodMetadata md = super.parseAndValidateMetadata(targetType, method);
RequestMapping classAnnotation = findMergedAnnotation(targetType,
@@ -213,6 +214,12 @@ public class SpringMvcContract extends Contract.BaseContract
@Override
protected void processAnnotationOnMethod(MethodMetadata data,
Annotation methodAnnotation, Method method) {
if (CollectionFormat.class.isInstance(methodAnnotation)) {
CollectionFormat collectionFormat = findMergedAnnotation(method,
CollectionFormat.class);
data.template().collectionFormat(collectionFormat.value());
}
if (!RequestMapping.class.isInstance(methodAnnotation) && !methodAnnotation
.annotationType().isAnnotationPresent(RequestMapping.class)) {
return;
@@ -248,13 +255,13 @@ public class SpringMvcContract extends Contract.BaseContract
// headers
parseHeaders(data, method, methodMapping);
data.indexToExpander(new LinkedHashMap<Integer, Param.Expander>());
data.indexToExpander(new LinkedHashMap<>());
}
private String resolve(String value) {
if (StringUtils.hasText(value)
&& this.resourceLoader instanceof ConfigurableApplicationContext) {
return ((ConfigurableApplicationContext) this.resourceLoader).getEnvironment()
&& resourceLoader instanceof ConfigurableApplicationContext) {
return ((ConfigurableApplicationContext) resourceLoader).getEnvironment()
.resolvePlaceholders(value);
}
return value;
@@ -280,9 +287,9 @@ public class SpringMvcContract extends Contract.BaseContract
AnnotatedParameterProcessor.AnnotatedParameterContext context = new SimpleAnnotatedParameterContext(
data, paramIndex);
Method method = this.processedMethods.get(data.configKey());
Method method = processedMethods.get(data.configKey());
for (Annotation parameterAnnotation : annotations) {
AnnotatedParameterProcessor processor = this.annotatedArgumentProcessors
AnnotatedParameterProcessor processor = annotatedArgumentProcessors
.get(parameterAnnotation.annotationType());
if (processor != null) {
Annotation processParameterAnnotation;
@@ -298,9 +305,8 @@ public class SpringMvcContract extends Contract.BaseContract
if (!isMultipartFormData(data) && isHttpAnnotation
&& data.indexToExpander().get(paramIndex) == null) {
TypeDescriptor typeDescriptor = createTypeDescriptor(method, paramIndex);
if (this.conversionService.canConvert(typeDescriptor,
STRING_TYPE_DESCRIPTOR)) {
Param.Expander expander = this.convertingExpanderFactory
if (conversionService.canConvert(typeDescriptor, STRING_TYPE_DESCRIPTOR)) {
Param.Expander expander = convertingExpanderFactory
.getExpander(typeDescriptor);
if (expander != null) {
data.indexToExpander().put(paramIndex, expander);
@@ -419,7 +425,7 @@ public class SpringMvcContract extends Contract.BaseContract
@Override
public String expand(Object value) {
return this.conversionService.convert(value, String.class);
return conversionService.convert(value, String.class);
}
}
@@ -434,7 +440,7 @@ public class SpringMvcContract extends Contract.BaseContract
Param.Expander getExpander(TypeDescriptor typeDescriptor) {
return value -> {
Object converted = this.conversionService.convert(value, typeDescriptor,
Object converted = conversionService.convert(value, typeDescriptor,
STRING_TYPE_DESCRIPTOR);
return (String) converted;
};
@@ -457,17 +463,17 @@ public class SpringMvcContract extends Contract.BaseContract
@Override
public MethodMetadata getMethodMetadata() {
return this.methodMetadata;
return methodMetadata;
}
@Override
public int getParameterIndex() {
return this.parameterIndex;
return parameterIndex;
}
@Override
public void setParameterName(String name) {
nameParam(this.methodMetadata, name, this.parameterIndex);
nameParam(methodMetadata, name, parameterIndex);
}
@Override

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2013-2020 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.cloud.openfeign.support;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.openfeign.CollectionFormat;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.test.NoSecurityConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.SocketUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Olga Maciaszek-Sharma
*/
@SpringBootTest(classes = PageableSupportTest.Config.class,
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class PageableSupportTest {
@Autowired
private PageableFeignClient feignClient;
@BeforeAll
public static void beforeClass() {
System.setProperty("server.port",
String.valueOf(SocketUtils.findAvailableTcpPort()));
}
@Test
void shouldProperlyFormatPageable() {
String direction = feignClient.performRequest(
PageRequest.of(1, 10, Sort.by(Sort.Order.desc("property"))));
assertThat(direction).isEqualTo("DESC");
}
@FeignClient(name = "pageable", url = "http://localhost:${server.port}/")
protected interface PageableFeignClient {
@CollectionFormat(feign.CollectionFormat.CSV)
@GetMapping(path = "/page")
String performRequest(Pageable page);
}
@SuppressWarnings("ConstantConditions")
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@RestController
@EnableFeignClients(clients = PageableFeignClient.class)
@Import(NoSecurityConfiguration.class)
protected static class Config {
@GetMapping(path = "/page")
String performRequest(Pageable page) {
return page.getSort().getOrderFor("property").getDirection().toString();
}
}
}

View File

@@ -37,6 +37,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.cloud.openfeign.CollectionFormat;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.annotation.DateTimeFormat;
@@ -62,6 +63,7 @@ import org.springframework.web.multipart.MultipartFile;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
import static feign.CollectionFormat.SSV;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assume.assumeTrue;
@@ -71,6 +73,7 @@ import static org.junit.Assume.assumeTrue;
* @author Aram Peres
* @author Aaron Whiteside
* @author Artyom Romanenko
* @author Olga Maciaszek-Sharma
*/
@RunWith(JUnitParamsRunner.class)
public class SpringMvcContractTests {
@@ -123,14 +126,14 @@ public class SpringMvcContractTests {
conversionServiceFactoryBean.afterPropertiesSet();
ConversionService conversionService = conversionServiceFactoryBean.getObject();
this.contract = new SpringMvcContract(Collections.emptyList(), conversionService);
contract = new SpringMvcContract(Collections.emptyList(), conversionService);
}
@Test
public void testProcessAnnotationOnMethod_Simple() throws Exception {
Method method = TestTemplate_Simple.class.getDeclaredMethod("getTest",
String.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/test/{id}");
@@ -143,7 +146,7 @@ public class SpringMvcContractTests {
public void testProcessAnnotations_Simple() throws Exception {
Method method = TestTemplate_Simple.class.getDeclaredMethod("getTest",
String.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/test/{id}");
@@ -158,7 +161,7 @@ public class SpringMvcContractTests {
public void testProcessAnnotations_SimpleGetMapping() throws Exception {
Method method = TestTemplate_Simple.class.getDeclaredMethod("getMappingTest",
String.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/test/{id}");
@@ -174,7 +177,7 @@ public class SpringMvcContractTests {
throws Exception {
Method method = TestTemplate_Class_Annotations.class
.getDeclaredMethod("getSpecificTest", String.class, String.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/prepend/{classId}/test/{testId}");
@@ -188,7 +191,7 @@ public class SpringMvcContractTests {
public void testProcessAnnotations_Class_AnnotationsGetAllTests() throws Exception {
Method method = TestTemplate_Class_Annotations.class
.getDeclaredMethod("getAllTests", String.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/prepend/{classId}");
@@ -201,12 +204,12 @@ public class SpringMvcContractTests {
public void testProcessAnnotations_ExtendedInterface() throws Exception {
Method extendedMethod = TestTemplate_Extended.class.getMethod("getAllTests",
String.class);
MethodMetadata extendedData = this.contract.parseAndValidateMetadata(
MethodMetadata extendedData = contract.parseAndValidateMetadata(
extendedMethod.getDeclaringClass(), extendedMethod);
Method method = TestTemplate_Class_Annotations.class
.getDeclaredMethod("getAllTests", String.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo(extendedData.template().url());
@@ -220,7 +223,7 @@ public class SpringMvcContractTests {
public void testProcessAnnotations_SimplePost() throws Exception {
Method method = TestTemplate_Simple.class.getDeclaredMethod("postTest",
TestObject.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/");
@@ -234,7 +237,7 @@ public class SpringMvcContractTests {
public void testProcessAnnotations_SimplePostMapping() throws Exception {
Method method = TestTemplate_Simple.class.getDeclaredMethod("postMappingTest",
TestObject.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/");
@@ -248,7 +251,7 @@ public class SpringMvcContractTests {
public void testProcessAnnotationsOnMethod_Advanced() throws Exception {
Method method = TestTemplate_Advanced.class.getDeclaredMethod("getTest",
String.class, String.class, Integer.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url())
@@ -263,16 +266,28 @@ public class SpringMvcContractTests {
throws Exception {
Method method = TestTemplate_Advanced.class.getDeclaredMethod("getTest",
String.class, String.class, Integer.class);
this.contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
// Don't throw an exception and this passes
}
@Test
public void testProcessAnnotationsOnMethod_CollectionFormat()
throws NoSuchMethodException {
Method method = TestTemplate_Advanced.class
.getDeclaredMethod("getWithCollectionFormat");
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().collectionFormat()).isEqualTo(SSV);
}
@Test
public void testProcessAnnotations_Advanced() throws Exception {
Method method = TestTemplate_Advanced.class.getDeclaredMethod("getTest",
String.class, String.class, Integer.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url())
@@ -297,7 +312,7 @@ public class SpringMvcContractTests {
public void testProcessAnnotations_Aliased() throws Exception {
Method method = TestTemplate_Advanced.class.getDeclaredMethod("getTest2",
String.class, Integer.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url())
@@ -320,7 +335,7 @@ public class SpringMvcContractTests {
public void testProcessAnnotations_DateTimeFormatParam() throws Exception {
Method method = TestTemplate_DateTimeFormatParameter.class
.getDeclaredMethod("getTest", LocalDateTime.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
Param.Expander expander = data.indexToExpander().get(0);
@@ -340,7 +355,7 @@ public class SpringMvcContractTests {
public void testProcessAnnotations_NumberFormatParam() throws Exception {
Method method = TestTemplate_NumberFormatParameter.class
.getDeclaredMethod("getTest", BigDecimal.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
Param.Expander expander = data.indexToExpander().get(0);
@@ -360,7 +375,7 @@ public class SpringMvcContractTests {
@Test
public void testProcessAnnotations_Advanced2() throws Exception {
Method method = TestTemplate_Advanced.class.getDeclaredMethod("getTest");
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/advanced");
@@ -372,7 +387,7 @@ public class SpringMvcContractTests {
@Test
public void testProcessAnnotations_Advanced3() throws Exception {
Method method = TestTemplate_Simple.class.getDeclaredMethod("getTest");
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/");
@@ -385,7 +400,7 @@ public class SpringMvcContractTests {
public void testProcessAnnotations_ListParams() throws Exception {
Method method = TestTemplate_ListParams.class.getDeclaredMethod("getTest",
List.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/test?id=" + "{id}");
@@ -398,7 +413,7 @@ public class SpringMvcContractTests {
public void testProcessAnnotations_ListParamsWithoutName() throws Exception {
Method method = TestTemplate_ListParamsWithoutName.class
.getDeclaredMethod("getTest", List.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/test?id=" + "{id}");
@@ -411,7 +426,7 @@ public class SpringMvcContractTests {
public void testProcessAnnotations_MapParams() throws Exception {
Method method = TestTemplate_MapParams.class.getDeclaredMethod("getTest",
Map.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/test");
@@ -424,7 +439,7 @@ public class SpringMvcContractTests {
public void testProcessHeaders() throws Exception {
Method method = TestTemplate_Headers.class.getDeclaredMethod("getTest",
String.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/test/{id}");
@@ -437,7 +452,7 @@ public class SpringMvcContractTests {
public void testProcessHeadersWithoutValues() throws Exception {
Method method = TestTemplate_HeadersWithoutValues.class
.getDeclaredMethod("getTest", String.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/test/{id}");
@@ -453,7 +468,7 @@ public class SpringMvcContractTests {
assumeTrue("does not have java 8 parameter names",
hasJava8ParameterNames(method));
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url())
@@ -477,7 +492,7 @@ public class SpringMvcContractTests {
public void testProcessHeaderMap() throws Exception {
Method method = TestTemplate_HeaderMap.class.getDeclaredMethod("headerMap",
MultiValueMap.class, String.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/headerMap");
@@ -491,14 +506,14 @@ public class SpringMvcContractTests {
public void testProcessHeaderMapMoreThanOnce() throws Exception {
Method method = TestTemplate_HeaderMap.class.getDeclaredMethod(
"headerMapMoreThanOnce", MultiValueMap.class, MultiValueMap.class);
this.contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
}
@Test
public void testProcessQueryMap() throws Exception {
Method method = TestTemplate_QueryMap.class.getDeclaredMethod("queryMap",
MultiValueMap.class, String.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/queryMap?aParam=" + "{aParam}");
@@ -512,7 +527,7 @@ public class SpringMvcContractTests {
public void testProcessQueryMapObject() throws Exception {
Method method = TestTemplate_QueryMap.class.getDeclaredMethod("queryMapObject",
TestObject.class, String.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url())
@@ -527,14 +542,14 @@ public class SpringMvcContractTests {
public void testProcessQueryMapMoreThanOnce() throws Exception {
Method method = TestTemplate_QueryMap.class.getDeclaredMethod(
"queryMapMoreThanOnce", MultiValueMap.class, MultiValueMap.class);
this.contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
}
@Test
public void testMatrixVariable_MapParam() throws Exception {
Method method = TestTemplate_MatrixVariable.class
.getDeclaredMethod("matrixVariable", Map.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
Map<String, String> testMap = new HashMap<>();
@@ -550,7 +565,7 @@ public class SpringMvcContractTests {
public void testMatrixVariable_ObjectParam() throws Exception {
Method method = TestTemplate_MatrixVariable.class
.getDeclaredMethod("matrixVariableObject", Object.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().method()).isEqualTo("GET");
@@ -563,7 +578,7 @@ public class SpringMvcContractTests {
public void testMatrixVariableWithNoName() throws NoSuchMethodException {
Method method = TestTemplate_MatrixVariable.class
.getDeclaredMethod("matrixVariableNotNamed", Map.class);
MethodMetadata data = this.contract
MethodMetadata data = contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
Map<String, String> testMap = new HashMap<>();
@@ -774,6 +789,10 @@ public class SpringMvcContractTests {
@RequestMapping("/advanced")
public interface TestTemplate_Advanced {
@CollectionFormat(SSV)
@GetMapping
ResponseEntity<TestObject> getWithCollectionFormat();
@ExceptionHandler
@RequestMapping(path = "/test/{id}", method = RequestMethod.PUT,
produces = MediaType.APPLICATION_JSON_VALUE)
@@ -883,11 +902,10 @@ public class SpringMvcContractTests {
TestObject that = (TestObject) o;
if (this.number != null ? !this.number.equals(that.number)
: that.number != null) {
if (number != null ? !number.equals(that.number) : that.number != null) {
return false;
}
if (this.something != null ? !this.something.equals(that.something)
if (something != null ? !something.equals(that.something)
: that.something != null) {
return false;
}
@@ -897,16 +915,16 @@ public class SpringMvcContractTests {
@Override
public int hashCode() {
int result = (this.something != null ? this.something.hashCode() : 0);
result = 31 * result + (this.number != null ? this.number.hashCode() : 0);
int result = (something != null ? something.hashCode() : 0);
result = 31 * result + (number != null ? number.hashCode() : 0);
return result;
}
@Override
public String toString() {
return new StringBuilder("TestObject{").append("something='")
.append(this.something).append("', ").append("number=")
.append(this.number).append("}").toString();
.append(something).append("', ").append("number=").append(number)
.append("}").toString();
}
}