diff --git a/ezyhttp-server-core/src/main/java/com/tvd12/ezyhttp/server/core/annotation/DoGet.java b/ezyhttp-server-core/src/main/java/com/tvd12/ezyhttp/server/core/annotation/DoGet.java index 1041aa4b..01dcd0c6 100644 --- a/ezyhttp-server-core/src/main/java/com/tvd12/ezyhttp/server/core/annotation/DoGet.java +++ b/ezyhttp-server-core/src/main/java/com/tvd12/ezyhttp/server/core/annotation/DoGet.java @@ -23,6 +23,13 @@ */ String uri() default ""; + /** + * other request uris. + * + * @return the other request uris + */ + String[] otherUris() default ""; + /** * accepted request body types. * diff --git a/ezyhttp-server-core/src/main/java/com/tvd12/ezyhttp/server/core/asm/RequestHandlersImplementer.java b/ezyhttp-server-core/src/main/java/com/tvd12/ezyhttp/server/core/asm/RequestHandlersImplementer.java index 83eba7fa..37cb0feb 100644 --- a/ezyhttp-server-core/src/main/java/com/tvd12/ezyhttp/server/core/asm/RequestHandlersImplementer.java +++ b/ezyhttp-server-core/src/main/java/com/tvd12/ezyhttp/server/core/asm/RequestHandlersImplementer.java @@ -1,11 +1,5 @@ package com.tvd12.ezyhttp.server.core.asm; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import com.tvd12.ezyfox.util.EzyLoggable; import com.tvd12.ezyhttp.core.constant.HttpMethod; import com.tvd12.ezyhttp.server.core.handler.RequestHandler; @@ -14,9 +8,10 @@ import com.tvd12.ezyhttp.server.core.reflect.RequestHandlerMethod; import com.tvd12.ezyhttp.server.core.request.RequestURI; import com.tvd12.ezyhttp.server.core.request.RequestURIMeta; - import lombok.Setter; +import java.util.*; + public class RequestHandlersImplementer extends EzyLoggable { @Setter @@ -40,7 +35,14 @@ public Map> implement(Object controller) { Map> handlers = new HashMap<>(); ControllerProxy proxy = new ControllerProxy(controller); String feature = proxy.getFeature(); + List requestHandlerMethods = new ArrayList<>(); for (RequestHandlerMethod method : proxy.getRequestHandlerMethods()) { + requestHandlerMethods.add(method); + requestHandlerMethods.addAll( + method.duplicatedToOtherRequestHandlerMethods() + ); + } + for (RequestHandlerMethod method : requestHandlerMethods) { RequestHandlerImplementer implementer = newImplementer(proxy, method); RequestHandler handler = implementer.implement(); HttpMethod httpMethod = handler.getMethod(); diff --git a/ezyhttp-server-core/src/main/java/com/tvd12/ezyhttp/server/core/reflect/RequestHandlerMethod.java b/ezyhttp-server-core/src/main/java/com/tvd12/ezyhttp/server/core/reflect/RequestHandlerMethod.java index 06fb7dda..d7d5e169 100644 --- a/ezyhttp-server-core/src/main/java/com/tvd12/ezyhttp/server/core/reflect/RequestHandlerMethod.java +++ b/ezyhttp-server-core/src/main/java/com/tvd12/ezyhttp/server/core/reflect/RequestHandlerMethod.java @@ -3,32 +3,50 @@ import com.tvd12.ezyfox.annotation.EzyFeature; import com.tvd12.ezyfox.annotation.EzyManagement; import com.tvd12.ezyfox.annotation.EzyPayment; +import com.tvd12.ezyfox.io.EzyStrings; import com.tvd12.ezyfox.reflect.EzyMethod; import com.tvd12.ezyhttp.core.constant.HttpMethod; -import com.tvd12.ezyhttp.core.net.URIBuilder; -import com.tvd12.ezyhttp.server.core.annotation.Api; -import com.tvd12.ezyhttp.server.core.annotation.Async; -import com.tvd12.ezyhttp.server.core.annotation.Authenticated; -import com.tvd12.ezyhttp.server.core.annotation.DoDelete; -import com.tvd12.ezyhttp.server.core.annotation.DoGet; -import com.tvd12.ezyhttp.server.core.annotation.DoPost; -import com.tvd12.ezyhttp.server.core.annotation.DoPut; +import com.tvd12.ezyhttp.server.core.annotation.*; import com.tvd12.ezyhttp.server.core.util.DoDeleteAnnotations; import com.tvd12.ezyhttp.server.core.util.DoGetAnnotations; import com.tvd12.ezyhttp.server.core.util.DoPostAnnotations; import com.tvd12.ezyhttp.server.core.util.DoPutAnnotations; - import lombok.Getter; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static com.tvd12.ezyfox.io.EzyLists.newArrayList; +import static com.tvd12.ezyhttp.core.net.URIBuilder.normalizePath; + @Getter public class RequestHandlerMethod extends HandlerMethod { + protected final String rootURI; protected final String requestURI; protected final String responseType; protected final HttpMethod httpMethod; + private RequestHandlerMethod( + String rootURI, + String requestURI, + HttpMethod httpMethod, + String responseType, + EzyMethod method + ) { + super(method); + this.rootURI = rootURI; + this.httpMethod = httpMethod; + this.responseType = responseType; + this.requestURI = normalizePath(rootURI + requestURI); + } + public RequestHandlerMethod(String rootURI, EzyMethod method) { super(method); + this.rootURI = rootURI; this.requestURI = fetchRequestURI(rootURI); this.httpMethod = fetchHttpMethod(); this.responseType = fetchResponseType(); @@ -36,7 +54,7 @@ public RequestHandlerMethod(String rootURI, EzyMethod method) { protected String fetchRequestURI(String rootURI) { String uri = rootURI + fetchRequestURIFragment(); - return URIBuilder.normalizePath(uri); + return normalizePath(uri); } protected String fetchRequestURIFragment() { @@ -89,6 +107,30 @@ protected String fetchResponseType() { return DoDeleteAnnotations.getResponseType(doDelete); } + public List duplicatedToOtherRequestHandlerMethods() { + return newArrayList( + fetchOtherRequestURIs(), + it -> new RequestHandlerMethod( + rootURI, + it, + httpMethod, + responseType, + method + ) + ); + } + + protected Set fetchOtherRequestURIs() { + DoGet doGet = method.getAnnotation(DoGet.class); + if (doGet == null) { + return Collections.emptySet(); + } + return Stream + .of(doGet.otherUris()) + .filter(EzyStrings::isNotBlank) + .collect(Collectors.toSet()); + } + public boolean isApi() { return method.isAnnotated(Api.class); } diff --git a/ezyhttp-server-core/src/test/java/com/tvd12/ezyhttp/server/core/test/asm/RequestHandlersImplementerTest.java b/ezyhttp-server-core/src/test/java/com/tvd12/ezyhttp/server/core/test/asm/RequestHandlersImplementerTest.java index 63ccc720..79b0fd33 100644 --- a/ezyhttp-server-core/src/test/java/com/tvd12/ezyhttp/server/core/test/asm/RequestHandlersImplementerTest.java +++ b/ezyhttp-server-core/src/test/java/com/tvd12/ezyhttp/server/core/test/asm/RequestHandlersImplementerTest.java @@ -1,18 +1,22 @@ package com.tvd12.ezyhttp.server.core.test.asm; -import java.util.Arrays; -import java.util.Collections; - -import org.testng.annotations.Test; - +import com.tvd12.ezyfox.collect.Sets; import com.tvd12.ezyhttp.core.constant.HttpMethod; +import com.tvd12.ezyhttp.server.core.annotation.Api; import com.tvd12.ezyhttp.server.core.annotation.DoGet; import com.tvd12.ezyhttp.server.core.asm.RequestHandlersImplementer; import com.tvd12.ezyhttp.server.core.exception.DuplicateURIMappingHandlerException; +import com.tvd12.ezyhttp.server.core.handler.RequestHandler; import com.tvd12.ezyhttp.server.core.handler.RequestURIDecorator; import com.tvd12.ezyhttp.server.core.manager.RequestHandlerManager; import com.tvd12.ezyhttp.server.core.request.RequestURI; import com.tvd12.test.assertion.Asserts; +import org.testng.annotations.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; import static org.mockito.Mockito.*; @@ -91,6 +95,58 @@ public void implementOneWithURIDecorator() { Asserts.assertThat(manager.getHandlerListByURI().get(uri).size()).isEqualsTo(2); } + @Test + public void implementOthersTest() { + // given + RequestHandlersImplementer sut = new RequestHandlersImplementer(); + Controller4 controller = new Controller4(); + + // when + Map> handlers = sut.implement( + Collections.singletonList(controller) + ); + + // then + Asserts.assertEquals(handlers.size(), 3); + Asserts.assertEquals( + handlers.keySet(), + Sets.newHashSet( + new RequestURI(HttpMethod.GET, "/get", false, false, true, null), + new RequestURI(HttpMethod.GET, "/hello", false, false, true, null), + new RequestURI(HttpMethod.GET, "/world", false, false, true, null) + ), + false + ); + } + + @Test + public void implementOthersWithURIDecorator() { + // given + RequestHandlersImplementer sut = new RequestHandlersImplementer(); + Controller4 controller = new Controller4(); + RequestHandlerManager manager = new RequestHandlerManager(); + manager.setAllowOverrideURI(true); + + RequestURIDecorator requestURIDecorator = mock(RequestURIDecorator.class); + when(requestURIDecorator.decorate(any(), any())).thenReturn("hello-world"); + sut.setRequestURIDecorator(requestURIDecorator); + + // when + Map> handlers = sut.implement( + Collections.singletonList(controller) + ); + + // then + Asserts.assertEquals(handlers.size(), 1); + Asserts.assertEquals( + handlers.keySet(), + Sets.newHashSet( + new RequestURI(HttpMethod.GET, "hello-world", false, false, true, null) + ), + false + ); + } + public static class Controller { @DoGet("/get") @@ -115,4 +171,12 @@ public static class Controller3 { public void doGet() { } } + + public static class Controller4 { + + @Api + @DoGet(uri = "/get", otherUris = {"/hello", "/world"}) + public void doGet() { + } + } } diff --git a/ezyhttp-server-core/src/test/java/com/tvd12/ezyhttp/server/core/test/reflect/RequestHandlerMethodTest.java b/ezyhttp-server-core/src/test/java/com/tvd12/ezyhttp/server/core/test/reflect/RequestHandlerMethodTest.java index c4e6f847..2a5e7aa9 100644 --- a/ezyhttp-server-core/src/test/java/com/tvd12/ezyhttp/server/core/test/reflect/RequestHandlerMethodTest.java +++ b/ezyhttp-server-core/src/test/java/com/tvd12/ezyhttp/server/core/test/reflect/RequestHandlerMethodTest.java @@ -1,14 +1,18 @@ package com.tvd12.ezyhttp.server.core.test.reflect; -import org.testng.annotations.Test; - import com.tvd12.ezyfox.annotation.EzyFeature; import com.tvd12.ezyfox.annotation.EzyPayment; +import com.tvd12.ezyfox.collect.Sets; import com.tvd12.ezyfox.reflect.EzyMethod; +import com.tvd12.ezyhttp.server.core.annotation.DoGet; import com.tvd12.ezyhttp.server.core.annotation.DoPost; import com.tvd12.ezyhttp.server.core.reflect.RequestHandlerMethod; import com.tvd12.test.assertion.Asserts; import com.tvd12.test.base.BaseTest; +import org.testng.annotations.Test; + +import java.util.Collections; +import java.util.stream.Collectors; public class RequestHandlerMethodTest extends BaseTest { @@ -41,6 +45,50 @@ public void isPaymentAndFeatureTest() throws Exception { Asserts.assertEquals(sut.getFeature(), "hello.world"); } + @Test + public void doGetAnnotationTest() throws Exception { + // given + RequestHandlerMethod sut = new RequestHandlerMethod( + "/root", + new EzyMethod(InternalController.class.getDeclaredMethod("getHello")) + ); + + // when + // then + Asserts.assertEquals(sut.getRequestURI(), "/root/hello"); + Asserts.assertEquals( + sut.duplicatedToOtherRequestHandlerMethods(), + Collections.emptySet(), + false + ); + } + + @Test + public void doGetAnnotationWithOtherUrisTest() throws Exception { + // given + RequestHandlerMethod sut = new RequestHandlerMethod( + "/root", + new EzyMethod(InternalController.class.getDeclaredMethod("getHelloWithOtherUris")) + ); + + // when + // then + Asserts.assertEquals(sut.getRequestURI(), "/root/hello"); + Asserts.assertEquals( + sut.duplicatedToOtherRequestHandlerMethods() + .stream() + .map(RequestHandlerMethod::getRequestURI) + .collect(Collectors.toSet()), + Sets.newHashSet( + "/root/world", + "/root/foo", + "/root/bar" + ), + false + ); + Asserts.assertEquals(sut.getRootURI(), "/root"); + } + public static class InternalController { @EzyPayment @@ -50,5 +98,11 @@ public void buySomething() {} @DoPost public void getSomething() {} + + @DoGet(value = "/hello") + public void getHello() {} + + @DoGet(value = "/hello", otherUris = {"/world", "/foo", "/bar"}) + public void getHelloWithOtherUris() {} } }