From 2dbe24a40de60abcf564f90bd7c3c420fc0e3605 Mon Sep 17 00:00:00 2001 From: Daniil Kudryavtsev Date: Fri, 4 Oct 2019 23:22:56 +0300 Subject: [PATCH] Add composed Spring annotations support (#1090) * Add composed Spring annotations support --- spring4/README.md | 15 ++++++ .../java/feign/spring/SpringContract.java | 47 +++++++++++++++---- .../java/feign/spring/SpringContractTest.java | 11 +++++ 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/spring4/README.md b/spring4/README.md index 3fde2209..877d7153 100644 --- a/spring4/README.md +++ b/spring4/README.md @@ -18,6 +18,21 @@ The ```consume``` adds the first value as the `Content-Type` header. #### `@RequestMapping` Appends the value to `Target.url()`. Can have tokens corresponding to `@PathVariable` annotations. The method sets the request method. +#### `@GetMapping` +Appends the value to `Target.url()`. Can have tokens corresponding to `@PathVariable` annotations. +Sets the `GET` request method. +#### `@PostMapping` +Appends the value to `Target.url()`. Can have tokens corresponding to `@PathVariable` annotations. +Sets the `POST` request method. +#### `@PutMapping` +Appends the value to `Target.url()`. Can have tokens corresponding to `@PathVariable` annotations. +Sets the `PUT` request method. +#### `@DeleteMapping` +Appends the value to `Target.url()`. Can have tokens corresponding to `@PathVariable` annotations. +Sets the `DELETE` request method. +#### `@PatchMapping` +Appends the value to `Target.url()`. Can have tokens corresponding to `@PathVariable` annotations. +Sets the `PATCH` request method. ### Parameter Annotations #### `@PathVariable` Links the value of the corresponding parameter to a template variable declared in the path. diff --git a/spring4/src/main/java/feign/spring/SpringContract.java b/spring4/src/main/java/feign/spring/SpringContract.java index f97f5c3a..86d1ba1e 100755 --- a/spring4/src/main/java/feign/spring/SpringContract.java +++ b/spring4/src/main/java/feign/spring/SpringContract.java @@ -13,19 +13,12 @@ */ package feign.spring; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import feign.Contract.BaseContract; +import org.springframework.web.bind.annotation.*; import feign.DeclarativeContract; import feign.MethodMetadata; +import feign.Request; public class SpringContract extends DeclarativeContract { @@ -51,6 +44,42 @@ public class SpringContract extends DeclarativeContract { data.template().method(requestMapping.method()[0].name()); }); + + registerMethodAnnotation(GetMapping.class, (mapping, data) -> { + appendMappings(data, mapping.value()); + data.template().method(Request.HttpMethod.GET); + handleProducesAnnotation(data, mapping.produces()); + handleConsumesAnnotation(data, mapping.consumes()); + }); + + registerMethodAnnotation(PostMapping.class, (mapping, data) -> { + appendMappings(data, mapping.value()); + data.template().method(Request.HttpMethod.POST); + handleProducesAnnotation(data, mapping.produces()); + handleConsumesAnnotation(data, mapping.consumes()); + }); + + registerMethodAnnotation(PutMapping.class, (mapping, data) -> { + appendMappings(data, mapping.value()); + data.template().method(Request.HttpMethod.PUT); + handleProducesAnnotation(data, mapping.produces()); + handleConsumesAnnotation(data, mapping.consumes()); + }); + + registerMethodAnnotation(DeleteMapping.class, (mapping, data) -> { + appendMappings(data, mapping.value()); + data.template().method(Request.HttpMethod.DELETE); + handleProducesAnnotation(data, mapping.produces()); + handleConsumesAnnotation(data, mapping.consumes()); + }); + + registerMethodAnnotation(PatchMapping.class, (mapping, data) -> { + appendMappings(data, mapping.value()); + data.template().method(Request.HttpMethod.PATCH); + handleProducesAnnotation(data, mapping.produces()); + handleConsumesAnnotation(data, mapping.consumes()); + }); + registerMethodAnnotation(ResponseBody.class, (body, data) -> { handleConsumesAnnotation(data, "application/json"); }); diff --git a/spring4/src/test/java/feign/spring/SpringContractTest.java b/spring4/src/test/java/feign/spring/SpringContractTest.java index 00a3f869..22528793 100755 --- a/spring4/src/test/java/feign/spring/SpringContractTest.java +++ b/spring4/src/test/java/feign/spring/SpringContractTest.java @@ -47,6 +47,7 @@ public class SpringContractTest { public void setup() throws IOException { mockClient = new MockClient() .noContent(HttpMethod.GET, "/health") + .noContent(HttpMethod.GET, "/health/1") .noContent(HttpMethod.GET, "/health/1?deep=true") .noContent(HttpMethod.GET, "/health/1?deep=true&dryRun=true") .ok(HttpMethod.GET, "/health/generic", "{}"); @@ -83,6 +84,13 @@ public class SpringContractTest { Arrays.asList("application/json"))); } + @Test + public void composedAnnotation() { + resource.check("1"); + + mockClient.verifyOne(HttpMethod.GET, "/health/1"); + } + @Test public void notAHttpMethod() { thrown.expectMessage("is not a method handled by feign"); @@ -115,6 +123,9 @@ public class SpringContractTest { @RequestParam(value = "deep", defaultValue = "false") boolean deepCheck, @RequestParam(value = "dryRun", defaultValue = "false") boolean dryRun); + @GetMapping(value = "/{id}") + public void check(@PathVariable("id") String campaignId); + @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "This customer is not found in the system") @ExceptionHandler(MissingResourceException.class)