Skip to content

Commit

Permalink
Exchange "Produces" and "Consumes" (#1772)
Browse files Browse the repository at this point in the history
* Exchange "Produces" and "Consumes"

* Added 'handleProducesAnnotation' and 'handleConsumesAnnotation' in the register of the method annotation 'RequestMapping'. And created a test case.

* Reformatted the codes

Co-authored-by: chengda <chengda@joysfintech.com>
Co-authored-by: Marvin Froeder <velo@users.noreply.github.com>
  • Loading branch information
3 people committed Oct 20, 2022
1 parent 853ae4c commit ca761ae
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 7 deletions.
7 changes: 5 additions & 2 deletions spring4/src/main/java/feign/spring/SpringContract.java
Expand Up @@ -44,6 +44,9 @@ public SpringContract() {

if (requestMapping.method().length == 1)
data.template().method(Request.HttpMethod.valueOf(requestMapping.method()[0].name()));

handleProducesAnnotation(data, requestMapping.produces());
handleConsumesAnnotation(data, requestMapping.consumes());
});


Expand Down Expand Up @@ -83,15 +86,15 @@ public SpringContract() {
});

registerMethodAnnotation(ResponseBody.class, (body, data) -> {
handleConsumesAnnotation(data, "application/json");
handleProducesAnnotation(data, "application/json");
});
registerMethodAnnotation(ExceptionHandler.class, (ann, data) -> {
data.ignoreMethod();
});
registerParameterAnnotation(PathVariable.class, pathVariableParameterAnnotationProcessor());

registerParameterAnnotation(RequestBody.class, (body, data, paramIndex) -> {
handleProducesAnnotation(data, "application/json");
handleConsumesAnnotation(data, "application/json");
});
registerParameterAnnotation(RequestParam.class, requestParamParameterAnnotationProcessor());
registerParameterAnnotation(RequestPart.class, requestPartParameterAnnotationProcessor());
Expand Down
60 changes: 55 additions & 5 deletions spring4/src/test/java/feign/spring/SpringContractTest.java
Expand Up @@ -16,17 +16,19 @@
import static org.hamcrest.Matchers.*;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import feign.Param;
import feign.*;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.*;
import feign.Feign;
import feign.Request;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.mock.HttpMethod;
Expand All @@ -44,6 +46,11 @@ public class SpringContractTest {

@Before
public void setup() throws IOException {
Response.Builder response = Response.builder()
.status(200)
.body("hello world", StandardCharsets.UTF_8)
.headers(Collections.singletonMap("Content-Type",
Collections.singletonList("text/plain")));
mockClient = new MockClient()
.noContent(HttpMethod.GET, "/health")
.noContent(HttpMethod.GET, "/health/1")
Expand All @@ -54,15 +61,46 @@ public void setup() throws IOException {
.noContent(HttpMethod.GET, "/health/header")
.noContent(HttpMethod.GET, "/health/header/map")
.noContent(HttpMethod.GET, "/health/header/pojo")
.ok(HttpMethod.GET, "/health/generic", "{}");
.ok(HttpMethod.GET, "/health/generic", "{}")
.add(HttpMethod.POST, "/health/text", response);
resource = Feign.builder()
.contract(new SpringContract())
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.mapAndDecode(new TextResponseMapper(), new JacksonDecoder())
.client(mockClient)
.target(new MockTarget<>(HealthResource.class));
}

class TextResponseMapper implements ResponseMapper {
@Override
public Response map(Response response, Type type) {
Map<String, Collection<String>> headers = response.headers();
if (headers == null || headers.isEmpty()) {
return response;
}
Collection<String> head = headers.get("Content-Type");
if (head == null || head.isEmpty()) {
return response;
}
String contentType = head.iterator().next();
if (contentType.startsWith("text/plain")) {
try {
Reader reader = response.body().asReader(StandardCharsets.UTF_8);
char[] buff = new char[1024];
String text = "";
int n = 0;
while ((n = reader.read(buff)) > 0) {
text += new String(buff, 0, n);
}
response = response.toBuilder().body("\"" + text + "\"", StandardCharsets.UTF_8).build();
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
return response;
}
}

@Test
public void noPath() {
resource.getStatus();
Expand Down Expand Up @@ -164,6 +202,14 @@ public void notAHttpMethod() {
resource.missingResourceExceptionHandler();
}

@Test
public void testConsumeAndProduce() {
resource.produceText(new HashMap<>());
Request request = mockClient.verifyOne(HttpMethod.POST, "/health/text");
assertThat(request.headers(), hasEntry("Content-Type", Arrays.asList("application/json")));
assertThat(request.headers(), hasEntry("Accept", Arrays.asList("text/plain")));
}

interface GenericResource<DTO> {

@RequestMapping(value = "generic", method = RequestMethod.GET)
Expand All @@ -178,6 +224,10 @@ interface HealthResource extends GenericResource<Data> {
@RequestMapping(method = RequestMethod.GET)
public @ResponseBody String getStatus();

@RequestMapping(method = RequestMethod.POST, value = "/text",
produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public String produceText(@RequestBody Map<String, Object> data);

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public void check(
@PathVariable("id") String campaignId,
Expand Down

0 comments on commit ca761ae

Please sign in to comment.