Skip to content

Commit 1803c11

Browse files
committed
fix: include all produces values in Accept header
Fixes gh-916 Signed-off-by: Olof Segergren <olle.segergren@gmail.com>
1 parent e9bfc34 commit 1803c11

2 files changed

Lines changed: 55 additions & 3 deletions

File tree

spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringMvcContract.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.util.List;
3131
import java.util.Map;
3232
import java.util.Objects;
33+
import java.util.stream.Collectors;
3334

3435
import feign.Contract;
3536
import feign.Feign;
@@ -93,6 +94,7 @@
9394
* @author Sam Kruglov
9495
* @author Tang Xiong
9596
* @author Juhyeong An
97+
* @author Olof Segergren
9698
*/
9799
public class SpringMvcContract extends Contract.BaseContract implements ResourceLoaderAware {
98100

@@ -417,9 +419,11 @@ private boolean queryMapParamPresent(MethodMetadata data) {
417419
}
418420

419421
private void parseProduces(MethodMetadata md, RequestMapping annotation) {
420-
String[] serverProduces = annotation.produces();
421-
String clientAccepts = serverProduces.length == 0 ? null : emptyToNull(serverProduces[0]);
422-
if (clientAccepts != null) {
422+
String clientAccepts = Arrays.stream(annotation.produces())
423+
.map(s -> emptyToNull(s))
424+
.filter(Objects::nonNull)
425+
.collect(Collectors.joining(", "));
426+
if (StringUtils.hasText(clientAccepts)) {
423427
md.template().header(ACCEPT, clientAccepts);
424428
}
425429
}

spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/SpringMvcContractTests.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,38 @@ void testAddingTemplatedParameterWithTheSameKey() throws NoSuchMethodException {
764764
assertThat(data.template().headers().get("Accept")).contains("application/json", "{Accept}");
765765
}
766766

767+
@Test
768+
void testMultipleProducesValues() throws NoSuchMethodException {
769+
Method method = TestTemplate_MultipleProduces.class.getDeclaredMethod("multipleProduces");
770+
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
771+
772+
assertThat(data.template().headers().get("Accept")).containsExactly("application/jose, application/json");
773+
}
774+
775+
@Test
776+
void testSingleProducesValueUnchanged() throws NoSuchMethodException {
777+
Method method = TestTemplate_MultipleProduces.class.getDeclaredMethod("singleProduces");
778+
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
779+
780+
assertThat(data.template().headers().get("Accept")).containsExactly(MediaType.APPLICATION_JSON_VALUE);
781+
}
782+
783+
@Test
784+
void testEmptyProducesNoAcceptHeader() throws NoSuchMethodException {
785+
Method method = TestTemplate_MultipleProduces.class.getDeclaredMethod("noProduces");
786+
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
787+
788+
assertThat(data.template().headers().get("Accept")).isNull();
789+
}
790+
791+
@Test
792+
void testProducesWithBlankEntryIgnored() throws NoSuchMethodException {
793+
Method method = TestTemplate_MultipleProduces.class.getDeclaredMethod("producesWithBlankEntry");
794+
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
795+
796+
assertThat(data.template().headers().get("Accept")).containsExactly("application/jose, application/json");
797+
}
798+
767799
@Test
768800
void testMultipleRequestPartAnnotations() throws NoSuchMethodException {
769801
Method method = TestTemplate_RequestPart.class.getDeclaredMethod("requestWithMultipleParts",
@@ -1141,4 +1173,20 @@ public String toString() {
11411173

11421174
}
11431175

1176+
public interface TestTemplate_MultipleProduces {
1177+
1178+
@GetMapping(value = "/test", produces = { "application/jose", "application/json" })
1179+
ResponseEntity<TestObject> multipleProduces();
1180+
1181+
@GetMapping(value = "/test", produces = MediaType.APPLICATION_JSON_VALUE)
1182+
ResponseEntity<TestObject> singleProduces();
1183+
1184+
@GetMapping("/test")
1185+
ResponseEntity<TestObject> noProduces();
1186+
1187+
@GetMapping(value = "/test", produces = { "application/jose", "", "application/json" })
1188+
ResponseEntity<TestObject> producesWithBlankEntry();
1189+
1190+
}
1191+
11441192
}

0 commit comments

Comments
 (0)