From 83cd4e7d77f980b349140d7ff5730c842b7cf7a6 Mon Sep 17 00:00:00 2001 From: BGuga Date: Tue, 12 Sep 2023 17:45:51 +0900 Subject: [PATCH 01/10] =?UTF-8?q?chore:=20reflection=20=ED=95=99=EC=8A=B5?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/reflection/Junit3TestRunner.java | 14 +++- .../java/reflection/Junit4TestRunner.java | 20 ++++- .../test/java/reflection/ReflectionTest.java | 83 +++++++++++++------ .../test/java/reflection/ReflectionsTest.java | 28 ++++++- 4 files changed, 117 insertions(+), 28 deletions(-) diff --git a/study/src/test/java/reflection/Junit3TestRunner.java b/study/src/test/java/reflection/Junit3TestRunner.java index b4e465240c..6176483092 100644 --- a/study/src/test/java/reflection/Junit3TestRunner.java +++ b/study/src/test/java/reflection/Junit3TestRunner.java @@ -1,5 +1,9 @@ package reflection; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; import org.junit.jupiter.api.Test; class Junit3TestRunner { @@ -7,7 +11,15 @@ class Junit3TestRunner { @Test void run() throws Exception { Class clazz = Junit3Test.class; + List methods = Arrays.stream(clazz.getMethods()) + .filter(method -> method.getName().startsWith("test")) + .collect(Collectors.toList()); - // TODO Junit3Test에서 test로 시작하는 메소드 실행 + Junit3Test junit3Test = clazz.getConstructor() + .newInstance(); + + for (Method method : methods) { + method.invoke(junit3Test); + } } } diff --git a/study/src/test/java/reflection/Junit4TestRunner.java b/study/src/test/java/reflection/Junit4TestRunner.java index 8a6916bc24..936ce2c3ea 100644 --- a/study/src/test/java/reflection/Junit4TestRunner.java +++ b/study/src/test/java/reflection/Junit4TestRunner.java @@ -1,5 +1,10 @@ package reflection; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; import org.junit.jupiter.api.Test; class Junit4TestRunner { @@ -7,7 +12,20 @@ class Junit4TestRunner { @Test void run() throws Exception { Class clazz = Junit4Test.class; + List methods = Arrays.stream(clazz.getMethods()) + .filter(method -> haveTestAnnotation(method)) + .collect(Collectors.toList()); - // TODO Junit4Test에서 @MyTest 애노테이션이 있는 메소드 실행 + Junit4Test junit4Test = clazz.getConstructor() + .newInstance(); + + for (Method method : methods) { + method.invoke(junit4Test); + } + } + + private boolean haveTestAnnotation(Method method) { + return Arrays.stream(method.getDeclaredAnnotations()) + .anyMatch(annotation -> annotation instanceof MyTest); } } diff --git a/study/src/test/java/reflection/ReflectionTest.java b/study/src/test/java/reflection/ReflectionTest.java index 370f0932b9..8690e1fb2e 100644 --- a/study/src/test/java/reflection/ReflectionTest.java +++ b/study/src/test/java/reflection/ReflectionTest.java @@ -1,5 +1,8 @@ package reflection; +import java.util.Arrays; +import java.util.Date; +import java.util.stream.Collectors; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,25 +22,27 @@ class ReflectionTest { void givenObject_whenGetsClassName_thenCorrect() { final Class clazz = Question.class; - assertThat(clazz.getSimpleName()).isEqualTo(""); - assertThat(clazz.getName()).isEqualTo(""); - assertThat(clazz.getCanonicalName()).isEqualTo(""); + assertThat(clazz.getSimpleName()).isEqualTo("Question"); + assertThat(clazz.getName()).isEqualTo("reflection.Question"); + assertThat(clazz.getCanonicalName()).isEqualTo("reflection.Question"); } @Test void givenClassName_whenCreatesObject_thenCorrect() throws ClassNotFoundException { final Class clazz = Class.forName("reflection.Question"); - assertThat(clazz.getSimpleName()).isEqualTo(""); - assertThat(clazz.getName()).isEqualTo(""); - assertThat(clazz.getCanonicalName()).isEqualTo(""); + assertThat(clazz.getSimpleName()).isEqualTo("Question"); + assertThat(clazz.getName()).isEqualTo("reflection.Question"); + assertThat(clazz.getCanonicalName()).isEqualTo("reflection.Question"); } @Test void givenObject_whenGetsFieldNamesAtRuntime_thenCorrect() { final Object student = new Student(); - final Field[] fields = null; - final List actualFieldNames = null; + final Field[] fields = student.getClass().getDeclaredFields(); + final List actualFieldNames = Arrays.stream(fields) + .map(Field::getName) + .collect(Collectors.toList()); assertThat(actualFieldNames).contains("name", "age"); } @@ -45,18 +50,20 @@ void givenObject_whenGetsFieldNamesAtRuntime_thenCorrect() { @Test void givenClass_whenGetsMethods_thenCorrect() { final Class animalClass = Student.class; - final Method[] methods = null; - final List actualMethods = null; + final Method[] methods = animalClass.getDeclaredMethods(); + final List actualMethods = Arrays.stream(methods) + .map(method -> method.getName()) + .collect(Collectors.toList()); assertThat(actualMethods) - .hasSize(3) - .contains("getAge", "toString", "getName"); + .hasSize(3) + .contains("getAge", "toString", "getName"); } @Test void givenClass_whenGetsAllConstructors_thenCorrect() { final Class questionClass = Question.class; - final Constructor[] constructors = null; + final Constructor[] constructors = questionClass.getDeclaredConstructors(); assertThat(constructors).hasSize(2); } @@ -65,11 +72,35 @@ void givenClass_whenGetsAllConstructors_thenCorrect() { void givenClass_whenInstantiatesObjectsAtRuntime_thenCorrect() throws Exception { final Class questionClass = Question.class; - final Constructor firstConstructor = null; - final Constructor secondConstructor = null; - - final Question firstQuestion = null; - final Question secondQuestion = null; + final Constructor firstConstructor = questionClass.getDeclaredConstructor( + String.class, + String.class, + String.class + ); + + final Constructor secondConstructor = questionClass.getDeclaredConstructor( + long.class, + String.class, + String.class, + String.class, + Date.class, + int.class + ); + + final Question firstQuestion = (Question) firstConstructor.newInstance( + "gugu", + "제목1", + "내용1" + ); + + final Question secondQuestion = (Question) secondConstructor.newInstance( + 1L, + "gugu", + "제목2", + "내용2", + new Date(), + 10 + ); assertThat(firstQuestion.getWriter()).isEqualTo("gugu"); assertThat(firstQuestion.getTitle()).isEqualTo("제목1"); @@ -82,7 +113,7 @@ void givenClass_whenInstantiatesObjectsAtRuntime_thenCorrect() throws Exception @Test void givenClass_whenGetsPublicFields_thenCorrect() { final Class questionClass = Question.class; - final Field[] fields = null; + final Field[] fields = questionClass.getFields(); assertThat(fields).hasSize(0); } @@ -90,7 +121,7 @@ void givenClass_whenGetsPublicFields_thenCorrect() { @Test void givenClass_whenGetsDeclaredFields_thenCorrect() { final Class questionClass = Question.class; - final Field[] fields = null; + final Field[] fields = questionClass.getDeclaredFields(); assertThat(fields).hasSize(6); assertThat(fields[0].getName()).isEqualTo("questionId"); @@ -99,7 +130,7 @@ void givenClass_whenGetsDeclaredFields_thenCorrect() { @Test void givenClass_whenGetsFieldsByName_thenCorrect() throws Exception { final Class questionClass = Question.class; - final Field field = null; + final Field field = questionClass.getDeclaredField("questionId"); assertThat(field.getName()).isEqualTo("questionId"); } @@ -107,7 +138,7 @@ void givenClass_whenGetsFieldsByName_thenCorrect() throws Exception { @Test void givenClassField_whenGetsType_thenCorrect() throws Exception { final Field field = Question.class.getDeclaredField("questionId"); - final Class fieldClass = null; + final Class fieldClass = field.getType(); assertThat(fieldClass.getSimpleName()).isEqualTo("long"); } @@ -115,15 +146,17 @@ void givenClassField_whenGetsType_thenCorrect() throws Exception { @Test void givenClassField_whenSetsAndGetsValue_thenCorrect() throws Exception { final Class studentClass = Student.class; - final Student student = null; - final Field field = null; + final Student student = (Student) studentClass.getDeclaredConstructor() + .newInstance(); + final Field field = student.getClass().getDeclaredField("age"); // todo field에 접근 할 수 있도록 만든다. + field.setAccessible(true); assertThat(field.getInt(student)).isZero(); assertThat(student.getAge()).isZero(); - field.set(null, null); + field.set(student, 99); assertThat(field.getInt(student)).isEqualTo(99); assertThat(student.getAge()).isEqualTo(99); diff --git a/study/src/test/java/reflection/ReflectionsTest.java b/study/src/test/java/reflection/ReflectionsTest.java index 5040c2ffa2..ffca91014c 100644 --- a/study/src/test/java/reflection/ReflectionsTest.java +++ b/study/src/test/java/reflection/ReflectionsTest.java @@ -1,9 +1,25 @@ package reflection; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.reflections.Reflections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import reflection.annotation.Controller; +import reflection.annotation.Repository; +import reflection.annotation.Service; +import reflection.examples.JdbcQuestionRepository; +import reflection.examples.JdbcUserRepository; +import reflection.examples.MyQnaService; +import reflection.examples.QnaController; class ReflectionsTest { @@ -12,7 +28,17 @@ class ReflectionsTest { @Test void showAnnotationClass() throws Exception { Reflections reflections = new Reflections("reflection.examples"); - // TODO 클래스 레벨에 @Controller, @Service, @Repository 애노테이션이 설정되어 모든 클래스 찾아 로그로 출력한다. + HashSet result = new HashSet<>(); + result.addAll(reflections.getTypesAnnotatedWith(Service.class)); + result.addAll(reflections.getTypesAnnotatedWith(Controller.class)); + result.addAll(reflections.getTypesAnnotatedWith(Repository.class)); + + assertAll( + () -> assertThat(result).contains(JdbcQuestionRepository.class), + () -> assertThat(result).contains(JdbcUserRepository.class), + () -> assertThat(result).contains(MyQnaService.class), + () -> assertThat(result).contains(QnaController.class) + ); } } From f384afeacae9d79763f666ccacb387dc14cfcb49 Mon Sep 17 00:00:00 2001 From: BGuga Date: Tue, 12 Sep 2023 19:30:47 +0900 Subject: [PATCH 02/10] =?UTF-8?q?chore:=20Servlet=20=ED=95=99=EC=8A=B5=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/servlet/com/example/CharacterEncodingFilter.java | 4 ++++ study/src/test/java/servlet/com/example/ServletTest.java | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/study/src/main/java/servlet/com/example/CharacterEncodingFilter.java b/study/src/main/java/servlet/com/example/CharacterEncodingFilter.java index cf4d886974..a017c44abb 100644 --- a/study/src/main/java/servlet/com/example/CharacterEncodingFilter.java +++ b/study/src/main/java/servlet/com/example/CharacterEncodingFilter.java @@ -8,9 +8,13 @@ @WebFilter("/*") public class CharacterEncodingFilter implements Filter { + public static final String DEFAULT_ENCODING = "UTF-8"; + @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.getServletContext().log("doFilter() 호출"); + request.setCharacterEncoding(DEFAULT_ENCODING); + response.setCharacterEncoding(DEFAULT_ENCODING); chain.doFilter(request, response); } } diff --git a/study/src/test/java/servlet/com/example/ServletTest.java b/study/src/test/java/servlet/com/example/ServletTest.java index 75fbb10dd5..e335f8190a 100644 --- a/study/src/test/java/servlet/com/example/ServletTest.java +++ b/study/src/test/java/servlet/com/example/ServletTest.java @@ -28,7 +28,7 @@ void testSharedCounter() { // expected를 0이 아닌 올바른 값으로 바꿔보자. // 예상한 결과가 나왔는가? 왜 이런 결과가 나왔을까? - assertThat(Integer.parseInt(response.body())).isEqualTo(0); + assertThat(Integer.parseInt(response.body())).isEqualTo(3); } @Test @@ -50,6 +50,6 @@ void testLocalCounter() { // expected를 0이 아닌 올바른 값으로 바꿔보자. // 예상한 결과가 나왔는가? 왜 이런 결과가 나왔을까? - assertThat(Integer.parseInt(response.body())).isEqualTo(0); + assertThat(Integer.parseInt(response.body())).isEqualTo(1); } } From 529d97e7f7bd1cabfca8bc7484111c02ae777e99 Mon Sep 17 00:00:00 2001 From: BGuga Date: Tue, 12 Sep 2023 21:54:34 +0900 Subject: [PATCH 03/10] =?UTF-8?q?feat:=20=ED=95=B8=EB=93=A4=EB=9F=AC=20?= =?UTF-8?q?=EB=A7=A4=ED=95=91=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mvc/tobe/AnnotationHandlerMapping.java | 137 ++++++++++++++++++ .../web/servlet/mvc/tobe/HandlerKey.java | 6 + 2 files changed, 143 insertions(+) diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java index a355218efa..85c29da5bc 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java @@ -1,11 +1,25 @@ package webmvc.org.springframework.web.servlet.mvc.tobe; +import context.org.springframework.stereotype.Controller; import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.function.BinaryOperator; +import java.util.stream.Collectors; +import org.reflections.Reflections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; +import web.org.springframework.web.bind.annotation.RequestMapping; +import webmvc.org.springframework.web.servlet.ModelAndView; public class AnnotationHandlerMapping { @@ -15,15 +29,138 @@ public class AnnotationHandlerMapping { private final Map handlerExecutions; public AnnotationHandlerMapping(final Object... basePackage) { + validateBasePackage(basePackage); this.basePackage = basePackage; this.handlerExecutions = new HashMap<>(); } + private void validateBasePackage(Object[] basePackage) { + for (Object o : basePackage) { + if (!(o instanceof String)) { + throw new IllegalArgumentException("basePackage 는 String 으로 입력해야 합니다"); + } + } + } + public void initialize() { log.info("Initialized AnnotationHandlerMapping!"); + handlerExecutions.putAll(findHandlersFrom(basePackage)); + } + + private Map findHandlersFrom(Object[] basePackage) { + List basePackages = convertToString(basePackage); + Map handlers = new HashMap<>(); + for (String targetPackage : basePackages) { + Map packageHandler = extractHandler(targetPackage); + checkDuplication(handlers, packageHandler); + handlers.putAll(packageHandler); + } + return handlers; + } + + private static List convertToString(Object[] basePackage) { + return Arrays.stream(basePackage) + .map(o -> (String) o) + .collect(Collectors.toList()); + } + + private void checkDuplication(Map originHandlers, + Map newHandlers) { + Set duplicatedHandlerKeys = new HashSet<>(originHandlers.keySet()); + duplicatedHandlerKeys.retainAll(newHandlers.keySet()); + if (!duplicatedHandlerKeys.isEmpty()) { + HandlerKey duplicatedHandlerKey = duplicatedHandlerKeys.iterator().next(); + log.error("duplication handler : {}", duplicatedHandlerKey); + throw new IllegalArgumentException("Duplicated HandlerKey"); + } + } + + private Map extractHandler(String targetPackage) { + Reflections reflections = new Reflections(targetPackage); + return reflections.getTypesAnnotatedWith(Controller.class).stream() + .map(this::extractHandlerFromClass) + .reduce( + new HashMap<>(), + migrateHandler()); + } + + private Map extractHandlerFromClass(Class targetClass) { + Object handler = makeClass(targetClass); + return Arrays.stream(targetClass.getMethods()) + .filter(this::haveRequestMapping) + .map(method -> extractHandlerFromMethod(method, handler)) + .reduce( + new HashMap<>(), + migrateHandler() + ); + } + + private Map extractHandlerFromMethod(Method method, + Object handler) { + RequestMapping requestMapping = method.getAnnotation(RequestMapping.class); + return Arrays.stream(requestMapping.method()) + .map(requestMethod -> { + Map extractedHandlerMapping = new HashMap<>(); + extractedHandlerMapping.put( + new HandlerKey(requestMapping.value(), requestMethod), + new HandlerExecutionImpl(handler, method) + ); + return extractedHandlerMapping; + }) + .reduce( + new HashMap<>(), + migrateHandler() + ); + } + + private BinaryOperator> migrateHandler() { + return (extractedHandler, extractingController) -> { + checkDuplication(extractedHandler, extractingController); + extractedHandler.putAll(extractingController); + return extractedHandler; + }; + } + + private Object makeClass(Class targetClass) { + try { + return targetClass.getDeclaredConstructor().newInstance(); + } catch (NoSuchMethodException | + InvocationTargetException | + InstantiationException | + IllegalAccessException e) { + throw new IllegalArgumentException(e); + } + } + + private boolean haveRequestMapping(Method method) { + return Arrays.stream(method.getDeclaredAnnotations()) + .anyMatch(RequestMapping.class::isInstance); } public Object getHandler(final HttpServletRequest request) { + Optional findHandler = handlerExecutions.keySet().stream() + .filter(handlerKey -> handlerKey.canHandle(request)) + .findAny(); + if (findHandler.isPresent()) { + return handlerExecutions.get(findHandler.get()); + } return null; } + + private class HandlerExecutionImpl extends HandlerExecution { + + private final Object handler; + private final Method handlerMethod; + + private HandlerExecutionImpl(Object handler, Method handlerMethod) { + this.handler = handler; + this.handlerMethod = handlerMethod; + } + + @Override + public ModelAndView handle(HttpServletRequest request, + HttpServletResponse response) throws Exception { + return (ModelAndView) handlerMethod.invoke(handler, request, response); + } + } } diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerKey.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerKey.java index 30d3c780ff..0a66e86b29 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerKey.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerKey.java @@ -1,5 +1,6 @@ package webmvc.org.springframework.web.servlet.mvc.tobe; +import jakarta.servlet.http.HttpServletRequest; import web.org.springframework.web.bind.annotation.RequestMethod; import java.util.Objects; @@ -14,6 +15,11 @@ public HandlerKey(final String url, final RequestMethod requestMethod) { this.requestMethod = requestMethod; } + public boolean canHandle(HttpServletRequest httpServletRequest){ + return httpServletRequest.getMethod().equals(requestMethod.name()) && + httpServletRequest.getRequestURI().equals(url); + } + @Override public String toString() { return "HandlerKey{" + From c2b6eab7fc985269ee92a4cce6871cc1e5fecce1 Mon Sep 17 00:00:00 2001 From: BGuga Date: Tue, 12 Sep 2023 22:06:17 +0900 Subject: [PATCH 04/10] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/duplicate/case1/TestController.java | 22 +++++++++++++++ .../java/duplicate/case2/TestController.java | 28 +++++++++++++++++++ .../tobe/AnnotationHandlerMappingTest.java | 22 +++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 mvc/src/test/java/duplicate/case1/TestController.java create mode 100644 mvc/src/test/java/duplicate/case2/TestController.java diff --git a/mvc/src/test/java/duplicate/case1/TestController.java b/mvc/src/test/java/duplicate/case1/TestController.java new file mode 100644 index 0000000000..ab89f06ea7 --- /dev/null +++ b/mvc/src/test/java/duplicate/case1/TestController.java @@ -0,0 +1,22 @@ +package duplicate.case1; + +import context.org.springframework.stereotype.Controller; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import web.org.springframework.web.bind.annotation.RequestMapping; +import web.org.springframework.web.bind.annotation.RequestMethod; +import webmvc.org.springframework.web.servlet.ModelAndView; + +@Controller +public class TestController { + + private static final Logger log = LoggerFactory.getLogger(samples.TestController.class); + + @RequestMapping(value = "/get-test", method = RequestMethod.GET) + public ModelAndView duplicatedMethod(final HttpServletRequest request, + final HttpServletResponse response) { + return null; + } +} diff --git a/mvc/src/test/java/duplicate/case2/TestController.java b/mvc/src/test/java/duplicate/case2/TestController.java new file mode 100644 index 0000000000..0e56116850 --- /dev/null +++ b/mvc/src/test/java/duplicate/case2/TestController.java @@ -0,0 +1,28 @@ +package duplicate.case2; + +import context.org.springframework.stereotype.Controller; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import web.org.springframework.web.bind.annotation.RequestMapping; +import web.org.springframework.web.bind.annotation.RequestMethod; +import webmvc.org.springframework.web.servlet.ModelAndView; + +@Controller +public class TestController { + + private static final Logger log = LoggerFactory.getLogger(samples.TestController.class); + + @RequestMapping(value = "/get-test", method = RequestMethod.GET) + public ModelAndView duplicatedMethod1(final HttpServletRequest request, + final HttpServletResponse response) { + return null; + } + + @RequestMapping(value = "/get-test", method = RequestMethod.GET) + public ModelAndView duplicatedMethod2(final HttpServletRequest request, + final HttpServletResponse response) { + return null; + } +} diff --git a/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMappingTest.java b/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMappingTest.java index dcec215a3f..494f21936f 100644 --- a/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMappingTest.java +++ b/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMappingTest.java @@ -6,6 +6,7 @@ import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -19,6 +20,27 @@ void setUp() { handlerMapping.initialize(); } + @Test + void methodDuplicationException_case1() { + // given & when & then + AnnotationHandlerMapping duplicatedHandlerMapping = new AnnotationHandlerMapping( + "samples", + "duplicate.case1"); + assertThatThrownBy(() -> duplicatedHandlerMapping.initialize()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Duplicated HandlerKey"); + } + + @Test + void methodDuplicationException_case2() { + // given & when & then + AnnotationHandlerMapping duplicatedHandlerMapping = new AnnotationHandlerMapping( + "duplicate.case2"); + assertThatThrownBy(() -> duplicatedHandlerMapping.initialize()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Duplicated HandlerKey"); + } + @Test void get() throws Exception { final var request = mock(HttpServletRequest.class); From d9ef3a5321213a579fb83f59e07e764c553aa72c Mon Sep 17 00:00:00 2001 From: BGuga Date: Wed, 13 Sep 2023 10:20:29 +0900 Subject: [PATCH 05/10] =?UTF-8?q?feat:=20HandlerExecution=20=EC=9E=AC?= =?UTF-8?q?=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/servlet/mvc/tobe/HandlerExecution.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerExecution.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerExecution.java index 37c583fbdf..1e45958aec 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerExecution.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerExecution.java @@ -2,11 +2,21 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import java.lang.reflect.Method; import webmvc.org.springframework.web.servlet.ModelAndView; public class HandlerExecution { - public ModelAndView handle(final HttpServletRequest request, final HttpServletResponse response) throws Exception { - return null; + private final Object handler; + private final Method handlerMethod; + + public HandlerExecution(Object handler, Method handlerMethod) { + this.handler = handler; + this.handlerMethod = handlerMethod; + } + + public ModelAndView handle(HttpServletRequest request, + HttpServletResponse response) throws Exception { + return (ModelAndView) handlerMethod.invoke(handler, request, response); } } From 9bc9b971bbca95f8289da022b5eb9ae0914b8bad Mon Sep 17 00:00:00 2001 From: BGuga Date: Wed, 13 Sep 2023 10:27:01 +0900 Subject: [PATCH 06/10] =?UTF-8?q?refactor:=20AnnotationHandlerMapping=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=A6=AC=ED=8C=A9=ED=84=B0?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mvc/tobe/AnnotationHandlerMapping.java | 90 ++++++++----------- 1 file changed, 39 insertions(+), 51 deletions(-) diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java index 85c29da5bc..2350a4040e 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java @@ -11,6 +11,7 @@ import java.util.Optional; import java.util.Set; import java.util.function.BinaryOperator; +import java.util.function.Function; import java.util.stream.Collectors; import org.reflections.Reflections; import org.slf4j.Logger; @@ -19,6 +20,7 @@ import java.util.HashMap; import java.util.Map; import web.org.springframework.web.bind.annotation.RequestMapping; +import web.org.springframework.web.bind.annotation.RequestMethod; import webmvc.org.springframework.web.servlet.ModelAndView; public class AnnotationHandlerMapping { @@ -64,6 +66,15 @@ private static List convertToString(Object[] basePackage) { .collect(Collectors.toList()); } + private Map extractHandler(String targetPackage) { + Reflections reflections = new Reflections(targetPackage); + return reflections.getTypesAnnotatedWith(Controller.class).stream() + .map(this::extractHandlerFromClass) + .reduce( + new HashMap<>(), + migrateHandler()); + } + private void checkDuplication(Map originHandlers, Map newHandlers) { Set duplicatedHandlerKeys = new HashSet<>(originHandlers.keySet()); @@ -75,15 +86,6 @@ private void checkDuplication(Map originHandlers, } } - private Map extractHandler(String targetPackage) { - Reflections reflections = new Reflections(targetPackage); - return reflections.getTypesAnnotatedWith(Controller.class).stream() - .map(this::extractHandlerFromClass) - .reduce( - new HashMap<>(), - migrateHandler()); - } - private Map extractHandlerFromClass(Class targetClass) { Object handler = makeClass(targetClass); return Arrays.stream(targetClass.getMethods()) @@ -95,24 +97,40 @@ private Map extractHandlerFromClass(Class targe ); } + private Object makeClass(Class targetClass) { + try { + return targetClass.getDeclaredConstructor().newInstance(); + } catch (NoSuchMethodException | + InvocationTargetException | + InstantiationException | + IllegalAccessException e) { + throw new IllegalArgumentException(e); + } + } + private Map extractHandlerFromMethod(Method method, Object handler) { - RequestMapping requestMapping = method.getAnnotation(RequestMapping.class); - return Arrays.stream(requestMapping.method()) - .map(requestMethod -> { - Map extractedHandlerMapping = new HashMap<>(); - extractedHandlerMapping.put( - new HandlerKey(requestMapping.value(), requestMethod), - new HandlerExecutionImpl(handler, method) - ); - return extractedHandlerMapping; - }) + return Arrays.stream(method.getAnnotation(RequestMapping.class).method()) + .map(makeHandler(method, handler, method.getAnnotation(RequestMapping.class))) .reduce( new HashMap<>(), migrateHandler() ); } + private Function> makeHandler(Method method, + Object handler, + RequestMapping requestMapping) { + return requestMethod -> { + Map extractedHandlerMapping = new HashMap<>(); + extractedHandlerMapping.put( + new HandlerKey(requestMapping.value(), requestMethod), + new HandlerExecution(handler, method) + ); + return extractedHandlerMapping; + }; + } + private BinaryOperator> migrateHandler() { return (extractedHandler, extractingController) -> { checkDuplication(extractedHandler, extractingController); @@ -121,17 +139,6 @@ private BinaryOperator> migrateHandler() { }; } - private Object makeClass(Class targetClass) { - try { - return targetClass.getDeclaredConstructor().newInstance(); - } catch (NoSuchMethodException | - InvocationTargetException | - InstantiationException | - IllegalAccessException e) { - throw new IllegalArgumentException(e); - } - } - private boolean haveRequestMapping(Method method) { return Arrays.stream(method.getDeclaredAnnotations()) .anyMatch(RequestMapping.class::isInstance); @@ -141,26 +148,7 @@ public Object getHandler(final HttpServletRequest request) { Optional findHandler = handlerExecutions.keySet().stream() .filter(handlerKey -> handlerKey.canHandle(request)) .findAny(); - if (findHandler.isPresent()) { - return handlerExecutions.get(findHandler.get()); - } - return null; - } - - private class HandlerExecutionImpl extends HandlerExecution { - - private final Object handler; - private final Method handlerMethod; - - private HandlerExecutionImpl(Object handler, Method handlerMethod) { - this.handler = handler; - this.handlerMethod = handlerMethod; - } - - @Override - public ModelAndView handle(HttpServletRequest request, - HttpServletResponse response) throws Exception { - return (ModelAndView) handlerMethod.invoke(handler, request, response); - } + return findHandler.map(handlerExecutions::get) + .orElse(null); } } From c852c27043d285d857852281ad2d61ff5c679bf2 Mon Sep 17 00:00:00 2001 From: BGuga Date: Wed, 13 Sep 2023 10:48:05 +0900 Subject: [PATCH 07/10] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mvc/tobe/AnnotationHandlerMapping.java | 2 -- .../java/duplicate/case3/TestController.java | 28 +++++++++++++++ mvc/src/test/java/samples/TestController.java | 17 ++++++++++ .../tobe/AnnotationHandlerMappingTest.java | 34 +++++++++++++++++-- 4 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 mvc/src/test/java/duplicate/case3/TestController.java diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java index 2350a4040e..05c6c91c63 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java @@ -2,7 +2,6 @@ import context.org.springframework.stereotype.Controller; import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; @@ -21,7 +20,6 @@ import java.util.Map; import web.org.springframework.web.bind.annotation.RequestMapping; import web.org.springframework.web.bind.annotation.RequestMethod; -import webmvc.org.springframework.web.servlet.ModelAndView; public class AnnotationHandlerMapping { diff --git a/mvc/src/test/java/duplicate/case3/TestController.java b/mvc/src/test/java/duplicate/case3/TestController.java new file mode 100644 index 0000000000..f65271beeb --- /dev/null +++ b/mvc/src/test/java/duplicate/case3/TestController.java @@ -0,0 +1,28 @@ +package duplicate.case3; + +import context.org.springframework.stereotype.Controller; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import web.org.springframework.web.bind.annotation.RequestMapping; +import web.org.springframework.web.bind.annotation.RequestMethod; +import webmvc.org.springframework.web.servlet.ModelAndView; + +@Controller +public class TestController { + + private static final Logger log = LoggerFactory.getLogger(samples.TestController.class); + + @RequestMapping(value = "/get-test", method = { + RequestMethod.GET, + RequestMethod.GET, + RequestMethod.GET, + RequestMethod.GET, + RequestMethod.GET + }) + public ModelAndView duplicatedMethod1(final HttpServletRequest request, + final HttpServletResponse response) { + return null; + } +} diff --git a/mvc/src/test/java/samples/TestController.java b/mvc/src/test/java/samples/TestController.java index 1f0e4acfb3..578582d34d 100644 --- a/mvc/src/test/java/samples/TestController.java +++ b/mvc/src/test/java/samples/TestController.java @@ -30,4 +30,21 @@ public ModelAndView save(final HttpServletRequest request, final HttpServletResp modelAndView.addObject("id", request.getAttribute("id")); return modelAndView; } + + @RequestMapping(value = "/multi-method-test", method = {RequestMethod.GET, RequestMethod.POST} ) + public ModelAndView multiHandle(final HttpServletRequest request, final HttpServletResponse response) { + log.info("test controller multi-handle method"); + String method = request.getMethod(); + if("GET".equals(method)){ + final var modelAndView = new ModelAndView(new JspView("")); + modelAndView.addObject("id", "getPooh"); + return modelAndView; + } + if("POST".equals(method)){ + final var modelAndView = new ModelAndView(new JspView("")); + modelAndView.addObject("id", "postPooh"); + return modelAndView; + } + throw new IllegalArgumentException("해당 요청을 Handling 할 수 없는 핸들러입니다."); + } } diff --git a/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMappingTest.java b/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMappingTest.java index 494f21936f..c69bcce2b0 100644 --- a/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMappingTest.java +++ b/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMappingTest.java @@ -21,7 +21,7 @@ void setUp() { } @Test - void methodDuplicationException_case1() { + void methodDuplicationException_existMappingInOtherClass_case1() { // given & when & then AnnotationHandlerMapping duplicatedHandlerMapping = new AnnotationHandlerMapping( "samples", @@ -32,7 +32,7 @@ void methodDuplicationException_case1() { } @Test - void methodDuplicationException_case2() { + void methodDuplicationException_existMappingIntSameClass_case2() { // given & when & then AnnotationHandlerMapping duplicatedHandlerMapping = new AnnotationHandlerMapping( "duplicate.case2"); @@ -41,6 +41,36 @@ void methodDuplicationException_case2() { .hasMessage("Duplicated HandlerKey"); } + @Test + void methodDuplicationException_duplicateMappingInOneMethod_case3() { + // given & when & then + AnnotationHandlerMapping duplicatedHandlerMapping = new AnnotationHandlerMapping( + "duplicate.case3"); + assertThatThrownBy(() -> duplicatedHandlerMapping.initialize()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Duplicated HandlerKey"); + } + + @Test + void oneMethodCanCreateManyHttpRequestMappings() throws Exception { + final var request = mock(HttpServletRequest.class); + final var response = mock(HttpServletResponse.class); + + when(request.getAttribute("id")).thenReturn("gugu"); + when(request.getRequestURI()).thenReturn("/multi-method-test"); + when(request.getMethod()).thenReturn("GET"); + + final var handlerExecution = (HandlerExecution) handlerMapping.getHandler(request); + final var getModelAndView = handlerExecution.handle(request, response); + + when(request.getMethod()).thenReturn("POST"); + + final var postModelAndView = handlerExecution.handle(request, response); + + assertThat(getModelAndView.getObject("id")).isEqualTo("getPooh"); + assertThat(postModelAndView.getObject("id")).isEqualTo("postPooh"); + } + @Test void get() throws Exception { final var request = mock(HttpServletRequest.class); From bb7f0b05e2ba0ed8ea2909b39412c18a60d6e64d Mon Sep 17 00:00:00 2001 From: BGuga Date: Wed, 13 Sep 2023 11:41:52 +0900 Subject: [PATCH 08/10] =?UTF-8?q?refactor:=20AnnotationHandlerMapping=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=A6=AC=ED=8C=A9=ED=84=B0?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mvc/tobe/AnnotationHandlerMapping.java | 113 ++++++------------ 1 file changed, 35 insertions(+), 78 deletions(-) diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java index 05c6c91c63..59f68f294c 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java @@ -5,21 +5,16 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; -import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.BinaryOperator; -import java.util.function.Function; -import java.util.stream.Collectors; import org.reflections.Reflections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import java.util.HashMap; -import java.util.Map; import web.org.springframework.web.bind.annotation.RequestMapping; -import web.org.springframework.web.bind.annotation.RequestMethod; public class AnnotationHandlerMapping { @@ -44,109 +39,71 @@ private void validateBasePackage(Object[] basePackage) { public void initialize() { log.info("Initialized AnnotationHandlerMapping!"); - handlerExecutions.putAll(findHandlersFrom(basePackage)); - } - - private Map findHandlersFrom(Object[] basePackage) { - List basePackages = convertToString(basePackage); - Map handlers = new HashMap<>(); - for (String targetPackage : basePackages) { - Map packageHandler = extractHandler(targetPackage); - checkDuplication(handlers, packageHandler); - handlers.putAll(packageHandler); - } - return handlers; - } - - private static List convertToString(Object[] basePackage) { - return Arrays.stream(basePackage) - .map(o -> (String) o) - .collect(Collectors.toList()); + handlerExecutions.putAll(extractHandler()); } - private Map extractHandler(String targetPackage) { - Reflections reflections = new Reflections(targetPackage); + private Map extractHandler() { + Reflections reflections = new Reflections(basePackage); return reflections.getTypesAnnotatedWith(Controller.class).stream() .map(this::extractHandlerFromClass) - .reduce( - new HashMap<>(), - migrateHandler()); - } - - private void checkDuplication(Map originHandlers, - Map newHandlers) { - Set duplicatedHandlerKeys = new HashSet<>(originHandlers.keySet()); - duplicatedHandlerKeys.retainAll(newHandlers.keySet()); - if (!duplicatedHandlerKeys.isEmpty()) { - HandlerKey duplicatedHandlerKey = duplicatedHandlerKeys.iterator().next(); - log.error("duplication handler : {}", duplicatedHandlerKey); - throw new IllegalArgumentException("Duplicated HandlerKey"); - } + .reduce(new HashMap<>(), migrateHandler()); } private Map extractHandlerFromClass(Class targetClass) { Object handler = makeClass(targetClass); - return Arrays.stream(targetClass.getMethods()) - .filter(this::haveRequestMapping) + return Arrays.stream(targetClass.getMethods()).filter(this::haveRequestMapping) .map(method -> extractHandlerFromMethod(method, handler)) - .reduce( - new HashMap<>(), - migrateHandler() - ); + .reduce(new HashMap<>(), migrateHandler()); } private Object makeClass(Class targetClass) { try { return targetClass.getDeclaredConstructor().newInstance(); - } catch (NoSuchMethodException | - InvocationTargetException | - InstantiationException | + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) { throw new IllegalArgumentException(e); } } - private Map extractHandlerFromMethod(Method method, - Object handler) { - return Arrays.stream(method.getAnnotation(RequestMapping.class).method()) - .map(makeHandler(method, handler, method.getAnnotation(RequestMapping.class))) - .reduce( - new HashMap<>(), - migrateHandler() - ); + private boolean haveRequestMapping(Method method) { + return Arrays.stream(method.getDeclaredAnnotations()) + .anyMatch(RequestMapping.class::isInstance); } - private Function> makeHandler(Method method, - Object handler, - RequestMapping requestMapping) { - return requestMethod -> { - Map extractedHandlerMapping = new HashMap<>(); - extractedHandlerMapping.put( - new HandlerKey(requestMapping.value(), requestMethod), - new HandlerExecution(handler, method) - ); - return extractedHandlerMapping; - }; + private Map extractHandlerFromMethod(Method method, Object handler) { + HandlerExecution handlerExecution = new HandlerExecution(handler, method); + RequestMapping annotation = method.getAnnotation(RequestMapping.class); + return Arrays.stream(annotation.method()) + .map(requestMethod -> { + Map extractedHandlerMapping = new HashMap<>(); + extractedHandlerMapping.put(new HandlerKey(annotation.value(), requestMethod), handlerExecution); + return extractedHandlerMapping; + }).reduce(new HashMap<>(), migrateHandler()); } private BinaryOperator> migrateHandler() { - return (extractedHandler, extractingController) -> { - checkDuplication(extractedHandler, extractingController); - extractedHandler.putAll(extractingController); - return extractedHandler; + return (originHandler, migrateHandler) -> { + checkDuplication(originHandler, migrateHandler); + originHandler.putAll(migrateHandler); + return originHandler; }; } - private boolean haveRequestMapping(Method method) { - return Arrays.stream(method.getDeclaredAnnotations()) - .anyMatch(RequestMapping.class::isInstance); + private void checkDuplication(Map originHandlers, + Map newHandlers) { + Set duplicatedHandlerKeys = new HashSet<>(originHandlers.keySet()); + duplicatedHandlerKeys.retainAll(newHandlers.keySet()); + if (!duplicatedHandlerKeys.isEmpty()) { + HandlerKey duplicatedHandlerKey = duplicatedHandlerKeys.iterator().next(); + log.error("duplication handler : {}", duplicatedHandlerKey); + throw new IllegalArgumentException("Duplicated HandlerKey"); + } } public Object getHandler(final HttpServletRequest request) { Optional findHandler = handlerExecutions.keySet().stream() .filter(handlerKey -> handlerKey.canHandle(request)) .findAny(); - return findHandler.map(handlerExecutions::get) - .orElse(null); + return findHandler.map(handlerExecutions::get).orElseGet(null); } } From 382863b9ed136c219b05a0c9d3a8d38dc4556ad7 Mon Sep 17 00:00:00 2001 From: BGuga Date: Thu, 14 Sep 2023 18:57:00 +0900 Subject: [PATCH 09/10] =?UTF-8?q?refactor:=20Method.isAnnotationPresent()?= =?UTF-8?q?=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../servlet/mvc/tobe/AnnotationHandlerMapping.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java index 59f68f294c..8bb2fded21 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java @@ -51,7 +51,8 @@ private Map extractHandler() { private Map extractHandlerFromClass(Class targetClass) { Object handler = makeClass(targetClass); - return Arrays.stream(targetClass.getMethods()).filter(this::haveRequestMapping) + return Arrays.stream(targetClass.getMethods()) + .filter(method -> method.isAnnotationPresent(RequestMapping.class)) .map(method -> extractHandlerFromMethod(method, handler)) .reduce(new HashMap<>(), migrateHandler()); } @@ -65,11 +66,6 @@ private Object makeClass(Class targetClass) { } } - private boolean haveRequestMapping(Method method) { - return Arrays.stream(method.getDeclaredAnnotations()) - .anyMatch(RequestMapping.class::isInstance); - } - private Map extractHandlerFromMethod(Method method, Object handler) { HandlerExecution handlerExecution = new HandlerExecution(handler, method); RequestMapping annotation = method.getAnnotation(RequestMapping.class); @@ -104,6 +100,7 @@ public Object getHandler(final HttpServletRequest request) { Optional findHandler = handlerExecutions.keySet().stream() .filter(handlerKey -> handlerKey.canHandle(request)) .findAny(); - return findHandler.map(handlerExecutions::get).orElseGet(null); + return findHandler.map(handlerExecutions::get) + .orElseGet(null); } } From 5d64428e664d248e6a23c58301ede65ba3ab5fc1 Mon Sep 17 00:00:00 2001 From: BGuga Date: Thu, 14 Sep 2023 19:58:49 +0900 Subject: [PATCH 10/10] =?UTF-8?q?refactor:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/servlet/mvc/tobe/AnnotationHandlerMapping.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java index 8bb2fded21..23f9417d43 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java @@ -50,14 +50,14 @@ private Map extractHandler() { } private Map extractHandlerFromClass(Class targetClass) { - Object handler = makeClass(targetClass); + Object handler = toInstance(targetClass); return Arrays.stream(targetClass.getMethods()) .filter(method -> method.isAnnotationPresent(RequestMapping.class)) .map(method -> extractHandlerFromMethod(method, handler)) .reduce(new HashMap<>(), migrateHandler()); } - private Object makeClass(Class targetClass) { + private Object toInstance(Class targetClass) { try { return targetClass.getDeclaredConstructor().newInstance(); } catch (NoSuchMethodException | InvocationTargetException | InstantiationException |