From a3acbed57845437ad6c3235b528567ac59458e85 Mon Sep 17 00:00:00 2001 From: hong-sile Date: Mon, 25 Sep 2023 13:55:59 +0900 Subject: [PATCH 01/18] =?UTF-8?q?feat:=20Jspview=EC=97=90=EC=84=9C=20rende?= =?UTF-8?q?r=EB=A5=BC=20=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../servlet/mvc/tobe/DispatcherServlet.java | 14 ++----- .../web/servlet/view/JspView.java | 10 +++-- .../web/servlet/view/JspViewTest.java | 37 +++++++++++++++++++ 3 files changed, 48 insertions(+), 13 deletions(-) create mode 100644 mvc/src/test/java/webmvc/org/springframework/web/servlet/view/JspViewTest.java diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/DispatcherServlet.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/DispatcherServlet.java index e25a01536a..84cb83e95b 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/DispatcherServlet.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/DispatcherServlet.java @@ -4,10 +4,10 @@ import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import webmvc.org.springframework.web.servlet.ModelAndView; -import webmvc.org.springframework.web.servlet.view.JspView; public class DispatcherServlet extends HttpServlet { @@ -35,7 +35,7 @@ protected void service(final HttpServletRequest request, final HttpServletRespon final var handler = handlerMappings.getHandler(request); final var modelAndView = handler.handle(request, response); move(modelAndView, request, response); - } catch (final Throwable e) { + } catch (final Exception e) { log.error("Exception : {}", e.getMessage(), e); throw new ServletException(e.getMessage()); } @@ -43,13 +43,7 @@ protected void service(final HttpServletRequest request, final HttpServletRespon private void move(final ModelAndView modelAndView, final HttpServletRequest request, final HttpServletResponse response) throws Exception { - final String viewName = modelAndView.getView().getViewName(); - if (viewName.startsWith(JspView.REDIRECT_PREFIX)) { - response.sendRedirect(viewName.substring(JspView.REDIRECT_PREFIX.length())); - return; - } - - final var requestDispatcher = request.getRequestDispatcher(viewName); - requestDispatcher.forward(request, response); + final Map model = modelAndView.getModel(); + modelAndView.getView().render(model, request, response); } } diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JspView.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JspView.java index b90018b983..0f4828e13f 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JspView.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JspView.java @@ -22,14 +22,18 @@ public JspView(final String viewName) { @Override public void render(final Map model, final HttpServletRequest request, final HttpServletResponse response) throws Exception { - // todo - model.keySet().forEach(key -> { log.debug("attribute name : {}, value : {}", key, model.get(key)); request.setAttribute(key, model.get(key)); }); - // todo + if (viewName.startsWith(JspView.REDIRECT_PREFIX)) { + response.sendRedirect(viewName.substring(JspView.REDIRECT_PREFIX.length())); + return; + } + + final var requestDispatcher = request.getRequestDispatcher(viewName); + requestDispatcher.forward(request, response); } @Override diff --git a/mvc/src/test/java/webmvc/org/springframework/web/servlet/view/JspViewTest.java b/mvc/src/test/java/webmvc/org/springframework/web/servlet/view/JspViewTest.java new file mode 100644 index 0000000000..2037bf37f0 --- /dev/null +++ b/mvc/src/test/java/webmvc/org/springframework/web/servlet/view/JspViewTest.java @@ -0,0 +1,37 @@ +package webmvc.org.springframework.web.servlet.view; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; + +class JspViewTest { + + private final HttpServletRequest request = mock(HttpServletRequest.class); + private final HttpServletResponse response = mock(HttpServletResponse.class); + + @Test + @DisplayName("JspView render Test") + void renderTest() throws Exception { + final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); + final RequestDispatcher requestDispatcher = mock(RequestDispatcher.class); + when(request.getRequestDispatcher(argumentCaptor.capture())) + .thenReturn(requestDispatcher); + final String viewName = "/register.jsp"; + final JspView jspView = new JspView(viewName); + + //when + jspView.render(Map.of(), request, response); + + //then + assertThat(argumentCaptor.getValue()) + .isEqualTo(viewName); + } +} From fd213a35182351ad141a6e73f1b8e350bb6e516c Mon Sep 17 00:00:00 2001 From: hong-sile Date: Mon, 25 Sep 2023 14:04:03 +0900 Subject: [PATCH 02/18] =?UTF-8?q?feat:=20UserController=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../techcourse/controller/UserController.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 app/src/main/java/com/techcourse/controller/UserController.java diff --git a/app/src/main/java/com/techcourse/controller/UserController.java b/app/src/main/java/com/techcourse/controller/UserController.java new file mode 100644 index 0000000000..cada0cc189 --- /dev/null +++ b/app/src/main/java/com/techcourse/controller/UserController.java @@ -0,0 +1,32 @@ +package com.techcourse.controller; + +import com.techcourse.domain.User; +import com.techcourse.repository.InMemoryUserRepository; +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; +import webmvc.org.springframework.web.servlet.view.JsonView; + +@Controller +public class UserController { + + private static final Logger log = LoggerFactory.getLogger(UserController.class); + + @RequestMapping(value = "/api/user", method = RequestMethod.GET) + public ModelAndView show(HttpServletRequest request, HttpServletResponse response) { + final String account = request.getParameter("account"); + log.debug("user id : {}", account); + + final ModelAndView modelAndView = new ModelAndView(new JsonView()); + final User user = InMemoryUserRepository.findByAccount(account) + .orElseThrow(); + + modelAndView.addObject("user", user); + return modelAndView; + } +} From 01619b8ff7c19a05f7f17e74365a49e8a217708c Mon Sep 17 00:00:00 2001 From: hong-sile Date: Mon, 25 Sep 2023 14:14:51 +0900 Subject: [PATCH 03/18] =?UTF-8?q?refactor:=20view=EC=9D=98=20getName=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../webmvc/org/springframework/web/servlet/View.java | 5 ++--- .../org/springframework/web/servlet/view/JsonView.java | 10 +++------- .../org/springframework/web/servlet/view/JspView.java | 5 ----- .../web/servlet/mvc/tobe/NotFoundHandlerTest.java | 7 +++++-- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/View.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/View.java index 0346a3dda8..2254e2da50 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/View.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/View.java @@ -2,11 +2,10 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; - import java.util.Map; public interface View { - void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception; - String getViewName(); + void render(Map model, HttpServletRequest request, HttpServletResponse response) + throws Exception; } diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java index f763743304..25d814667d 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java @@ -2,18 +2,14 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.View; - import java.util.Map; +import webmvc.org.springframework.web.servlet.View; public class JsonView implements View { @Override - public void render(final Map model, final HttpServletRequest request, HttpServletResponse response) throws Exception { - } + public void render(final Map model, final HttpServletRequest request, + final HttpServletResponse response) throws Exception { - @Override - public String getViewName() { - return null; } } diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JspView.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JspView.java index 0f4828e13f..a8cc3e6a71 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JspView.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JspView.java @@ -35,9 +35,4 @@ public void render(final Map model, final HttpServletRequest request, final var requestDispatcher = request.getRequestDispatcher(viewName); requestDispatcher.forward(request, response); } - - @Override - public String getViewName() { - return viewName; - } } diff --git a/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/NotFoundHandlerTest.java b/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/NotFoundHandlerTest.java index 2f79312fa0..6f8b01ebee 100644 --- a/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/NotFoundHandlerTest.java +++ b/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/NotFoundHandlerTest.java @@ -8,6 +8,7 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; import webmvc.org.springframework.web.servlet.ModelAndView; +import webmvc.org.springframework.web.servlet.view.JspView; class NotFoundHandlerTest { @@ -20,8 +21,10 @@ void handle() { final ModelAndView modelAndView = notFoundHandler.handle(request, response); - assertThat(modelAndView.getView().getViewName()) - .isEqualTo("redirect:/404.jsp"); + final JspView expectedJspView = new JspView("redirect:/404.jsp"); + assertThat(modelAndView.getView()) + .usingRecursiveComparison() + .isEqualTo(expectedJspView); } } From 413093bd6c7872e0a3bb5fa2b8ef55c6edd823da Mon Sep 17 00:00:00 2001 From: hong-sile Date: Mon, 25 Sep 2023 14:37:03 +0900 Subject: [PATCH 04/18] =?UTF-8?q?feat:=20jsonView=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/servlet/view/JsonView.java | 14 +++++ .../web/servlet/view/JsonViewTest.java | 62 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 mvc/src/test/java/webmvc/org/springframework/web/servlet/view/JsonViewTest.java diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java index 25d814667d..d5d5ae72e7 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java @@ -1,15 +1,29 @@ package webmvc.org.springframework.web.servlet.view; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.util.Map; +import web.org.springframework.http.MediaType; import webmvc.org.springframework.web.servlet.View; public class JsonView implements View { + private final ObjectMapper objectMapper = new ObjectMapper(); + @Override public void render(final Map model, final HttpServletRequest request, final HttpServletResponse response) throws Exception { + final String convertedModel = convertModel(model); + response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); + response.getWriter().write(convertedModel); + } + private String convertModel(final Map model) throws JsonProcessingException { + if (model.size() == 1) { + return objectMapper.writeValueAsString(model.values().toArray()[0]); + } + return objectMapper.writeValueAsString(model); } } diff --git a/mvc/src/test/java/webmvc/org/springframework/web/servlet/view/JsonViewTest.java b/mvc/src/test/java/webmvc/org/springframework/web/servlet/view/JsonViewTest.java new file mode 100644 index 0000000000..8d5b2634da --- /dev/null +++ b/mvc/src/test/java/webmvc/org/springframework/web/servlet/view/JsonViewTest.java @@ -0,0 +1,62 @@ +package webmvc.org.springframework.web.servlet.view; + +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import web.org.springframework.http.MediaType; + +class JsonViewTest { + + private final HttpServletRequest request = mock(HttpServletRequest.class); + private final HttpServletResponse response = mock(HttpServletResponse.class); + + @Test + @DisplayName("JspView render Test 값이 한개 일 떄") + void renderTest() throws Exception { + final JsonView jsonView = new JsonView(); + final Map model = new HashMap<>(); + final String stringObject = "string"; + final PrintWriter mockWriter = mock(PrintWriter.class); + given(response.getWriter()).willReturn(mockWriter); + model.put("string object", stringObject); + + //when + jsonView.render(model, request, response); + + //then + final String expectedValue = "\"string\""; + verify(mockWriter, times(1)).write(expectedValue); + verify(response, times(1)).setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); + } + + @Test + @DisplayName("JspView render Test 값이 두개 이상일 떄") + void renderTest2() throws Exception { + final JsonView jsonView = new JsonView(); + final Map model = new HashMap<>(); + final PrintWriter mockWriter = mock(PrintWriter.class); + given(response.getWriter()).willReturn(mockWriter); + model.put("string object1", "value1"); + model.put("string object2", "value2"); + + //when + jsonView.render(model, request, response); + + //then + final String expectedValue = String.join(System.lineSeparator(), "{" + + "\"string object1\":\"value1\"," + + "\"string object2\":\"value2\"" + + "}"); + verify(mockWriter, times(1)).write(expectedValue); + verify(response, times(1)).setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); + } +} From bb2fa6e1ac91d5e2974dc87f185a478649d6913b Mon Sep 17 00:00:00 2001 From: hong-sile Date: Mon, 25 Sep 2023 15:54:01 +0900 Subject: [PATCH 05/18] =?UTF-8?q?refactor:=20LoginController=20=EC=96=B4?= =?UTF-8?q?=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EA=B8=B0=EB=B0=98?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/LoginController.java | 41 ++++++++++++++----- .../controller/LoginViewController.java | 22 ---------- 2 files changed, 30 insertions(+), 33 deletions(-) delete mode 100644 app/src/main/java/com/techcourse/controller/LoginViewController.java diff --git a/app/src/main/java/com/techcourse/controller/LoginController.java b/app/src/main/java/com/techcourse/controller/LoginController.java index 0428fe109e..5c64b47e86 100644 --- a/app/src/main/java/com/techcourse/controller/LoginController.java +++ b/app/src/main/java/com/techcourse/controller/LoginController.java @@ -2,28 +2,47 @@ import com.techcourse.domain.User; import com.techcourse.repository.InMemoryUserRepository; +import context.org.springframework.stereotype.Controller; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; 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; +import webmvc.org.springframework.web.servlet.view.JspView; -public class LoginController implements Controller { +@Controller +public class LoginController { private static final Logger log = LoggerFactory.getLogger(LoginController.class); - @Override - public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception { + @RequestMapping(method = RequestMethod.GET, value = "/login/view") + public ModelAndView show(final HttpServletRequest req, final HttpServletResponse res) { + final String viewName = UserSession.getUserFrom(req.getSession()) + .map(user -> { + log.info("logged in {}", user.getAccount()); + return "redirect:/index.jsp"; + }) + .orElse("/login.jsp"); + return new ModelAndView(new JspView(viewName)); + } + + @RequestMapping(method = RequestMethod.POST, value = "/login") + public ModelAndView execute(final HttpServletRequest req, final HttpServletResponse res) + throws Exception { if (UserSession.isLoggedIn(req.getSession())) { - return "redirect:/index.jsp"; + return new ModelAndView(new JspView("redirect:/index.jsp")); } - return InMemoryUserRepository.findByAccount(req.getParameter("account")) - .map(user -> { - log.info("User : {}", user); - return login(req, user); - }) - .orElse("redirect:/401.jsp"); + final String viewName = InMemoryUserRepository.findByAccount(req.getParameter("account")) + .map(user -> { + log.info("User : {}", user); + return login(req, user); + }) + .orElse("redirect:/401.jsp"); + + return new ModelAndView(new JspView(viewName)); } private String login(final HttpServletRequest request, final User user) { diff --git a/app/src/main/java/com/techcourse/controller/LoginViewController.java b/app/src/main/java/com/techcourse/controller/LoginViewController.java deleted file mode 100644 index 86ec26cdce..0000000000 --- a/app/src/main/java/com/techcourse/controller/LoginViewController.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.techcourse.controller; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; - -public class LoginViewController implements Controller { - - private static final Logger log = LoggerFactory.getLogger(LoginViewController.class); - - @Override - public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception { - return UserSession.getUserFrom(req.getSession()) - .map(user -> { - log.info("logged in {}", user.getAccount()); - return "redirect:/index.jsp"; - }) - .orElse("/login.jsp"); - } -} From 9bb465a62940ca2d79811638d58e57c524257c5c Mon Sep 17 00:00:00 2001 From: hong-sile Date: Mon, 25 Sep 2023 16:03:27 +0900 Subject: [PATCH 06/18] =?UTF-8?q?feat:=20userController=EC=97=90=EC=84=9C?= =?UTF-8?q?=20user=20=EC=A0=84=EC=B2=B4=EC=9D=98=20=EA=B0=92=EC=9D=84=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=ED=95=98=EB=8F=84=EB=A1=9D=20getter=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/techcourse/domain/User.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/src/main/java/com/techcourse/domain/User.java b/app/src/main/java/com/techcourse/domain/User.java index beb0919b7e..d0325fbc54 100644 --- a/app/src/main/java/com/techcourse/domain/User.java +++ b/app/src/main/java/com/techcourse/domain/User.java @@ -18,10 +18,22 @@ public boolean checkPassword(String password) { return this.password.equals(password); } + public long getId() { + return id; + } + public String getAccount() { return account; } + public String getPassword() { + return password; + } + + public String getEmail() { + return email; + } + @Override public String toString() { return "User{" + From 9a033cdcd8499a5ad88a946793f3080479af4dac Mon Sep 17 00:00:00 2001 From: hong-sile Date: Mon, 25 Sep 2023 16:08:52 +0900 Subject: [PATCH 07/18] =?UTF-8?q?feat:=20forwardController=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../servlet/mvc/asis/ForwardController.java | 20 ------------------ .../servlet/mvc/tobe/ForwardController.java | 21 +++++++++++++++++++ 2 files changed, 21 insertions(+), 20 deletions(-) delete mode 100644 mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/ForwardController.java create mode 100644 mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/ForwardController.java diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/ForwardController.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/ForwardController.java deleted file mode 100644 index cd8f1ef371..0000000000 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/ForwardController.java +++ /dev/null @@ -1,20 +0,0 @@ -package webmvc.org.springframework.web.servlet.mvc.asis; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -import java.util.Objects; - -public class ForwardController implements Controller { - - private final String path; - - public ForwardController(final String path) { - this.path = Objects.requireNonNull(path); - } - - @Override - public String execute(final HttpServletRequest request, final HttpServletResponse response) { - return path; - } -} diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/ForwardController.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/ForwardController.java new file mode 100644 index 0000000000..207e89dc10 --- /dev/null +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/ForwardController.java @@ -0,0 +1,21 @@ +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 web.org.springframework.web.bind.annotation.RequestMapping; +import web.org.springframework.web.bind.annotation.RequestMethod; +import webmvc.org.springframework.web.servlet.ModelAndView; +import webmvc.org.springframework.web.servlet.view.JspView; + +@Controller +public class ForwardController { + + private static final String ROOT_DIR = "/index.jsp"; + + @RequestMapping(value = "/", method = RequestMethod.GET) + public ModelAndView show(final HttpServletRequest request, + final HttpServletResponse response) { + return new ModelAndView(new JspView(ROOT_DIR)); + } +} From b3f483caf3f3ab1bfb9b2e2eda9660eb276f1a4a Mon Sep 17 00:00:00 2001 From: hong-sile Date: Mon, 25 Sep 2023 16:11:11 +0900 Subject: [PATCH 08/18] =?UTF-8?q?feat:=20LogoutController=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../techcourse/controller/LogoutController.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/techcourse/controller/LogoutController.java b/app/src/main/java/com/techcourse/controller/LogoutController.java index 4642fd9450..2288b4df41 100644 --- a/app/src/main/java/com/techcourse/controller/LogoutController.java +++ b/app/src/main/java/com/techcourse/controller/LogoutController.java @@ -1,15 +1,20 @@ package com.techcourse.controller; +import context.org.springframework.stereotype.Controller; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; +import web.org.springframework.web.bind.annotation.RequestMapping; +import web.org.springframework.web.bind.annotation.RequestMethod; +import webmvc.org.springframework.web.servlet.ModelAndView; +import webmvc.org.springframework.web.servlet.view.JspView; -public class LogoutController implements Controller { +@Controller +public class LogoutController { - @Override - public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception { + @RequestMapping(method = RequestMethod.POST, value = "/logout") + public ModelAndView show(final HttpServletRequest req, final HttpServletResponse res) { final var session = req.getSession(); session.removeAttribute(UserSession.SESSION_KEY); - return "redirect:/"; + return new ModelAndView(new JspView("redirect:/")); } } From 88d5f8ed7982745223f8b1ae1a0baecb844bb4b1 Mon Sep 17 00:00:00 2001 From: hong-sile Date: Mon, 25 Sep 2023 16:14:51 +0900 Subject: [PATCH 09/18] =?UTF-8?q?refactor:=20registerController=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../techcourse/controller/RegisterController.java | 2 +- .../controller/RegisterViewController.java | 13 ------------- .../controller/RegisterControllerTest.java | 6 ++++-- 3 files changed, 5 insertions(+), 16 deletions(-) delete mode 100644 app/src/main/java/com/techcourse/controller/RegisterViewController.java diff --git a/app/src/main/java/com/techcourse/controller/RegisterController.java b/app/src/main/java/com/techcourse/controller/RegisterController.java index cdfaf7ab6f..5462446548 100644 --- a/app/src/main/java/com/techcourse/controller/RegisterController.java +++ b/app/src/main/java/com/techcourse/controller/RegisterController.java @@ -24,7 +24,7 @@ public ModelAndView save(final HttpServletRequest req, final HttpServletResponse return new ModelAndView(new JspView("redirect:/index.jsp")); } - @RequestMapping(value = "/register", method = RequestMethod.GET) + @RequestMapping(value = "/register/view", method = RequestMethod.GET) public ModelAndView show(HttpServletRequest req, HttpServletResponse res) { return new ModelAndView(new JspView("/register.jsp")); } diff --git a/app/src/main/java/com/techcourse/controller/RegisterViewController.java b/app/src/main/java/com/techcourse/controller/RegisterViewController.java deleted file mode 100644 index 136962136d..0000000000 --- a/app/src/main/java/com/techcourse/controller/RegisterViewController.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.techcourse.controller; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; - -public class RegisterViewController implements Controller { - - @Override - public String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception { - return "/register.jsp"; - } -} diff --git a/app/src/test/java/com/techcourse/controller/RegisterControllerTest.java b/app/src/test/java/com/techcourse/controller/RegisterControllerTest.java index 094ab544a9..bc78d4a171 100644 --- a/app/src/test/java/com/techcourse/controller/RegisterControllerTest.java +++ b/app/src/test/java/com/techcourse/controller/RegisterControllerTest.java @@ -56,10 +56,12 @@ void save() { final Optional savedUser = InMemoryUserRepository.findByAccount(account); final Optional expectedUser = Optional.of( new User(unvalidatedId, account, password, email)); + final JspView expectedJspView = new JspView("redirect:/index.jsp"); assertAll( - () -> assertThat(actual.getView().getViewName()) - .isEqualTo("redirect:/index.jsp"), + () -> assertThat(actual.getView()) + .usingRecursiveComparison() + .isEqualTo(expectedJspView), () -> assertThat(savedUser) .usingRecursiveComparison() .ignoringFields("value.id") From f5fdb663aa5f8b903390a3cb534abac2e54149be Mon Sep 17 00:00:00 2001 From: hong-sile Date: Mon, 25 Sep 2023 16:24:22 +0900 Subject: [PATCH 10/18] =?UTF-8?q?chore:=20HandlerMapping=EB=93=A4=20?= =?UTF-8?q?=ED=8C=A8=ED=82=A4=EC=A7=80=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AnnotationHandlerMapping.java | 12 +++++++++--- .../tobe/{ => handler_mapping}/HandlerMapping.java | 3 ++- .../tobe/{ => handler_mapping}/HandlerMappings.java | 4 +++- .../AnnotationHandlerMappingTest.java | 4 +++- 4 files changed, 17 insertions(+), 6 deletions(-) rename mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/{ => handler_mapping}/AnnotationHandlerMapping.java (80%) rename mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/{ => handler_mapping}/HandlerMapping.java (57%) rename mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/{ => handler_mapping}/HandlerMappings.java (81%) rename mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/{ => handler_mapping}/AnnotationHandlerMappingTest.java (88%) 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/handler_mapping/AnnotationHandlerMapping.java similarity index 80% rename from mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMapping.java rename to mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/AnnotationHandlerMapping.java index 34a0a6d151..fb7a6c198d 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/handler_mapping/AnnotationHandlerMapping.java @@ -1,4 +1,4 @@ -package webmvc.org.springframework.web.servlet.mvc.tobe; +package webmvc.org.springframework.web.servlet.mvc.tobe.handler_mapping; import static java.util.Map.entry; @@ -18,16 +18,22 @@ import web.org.springframework.web.bind.annotation.RequestMapping; import web.org.springframework.web.bind.annotation.RequestMethod; import webmvc.org.springframework.web.servlet.exception.RequestMethodNotValidException; +import webmvc.org.springframework.web.servlet.mvc.tobe.Handler; +import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerExecution; +import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerKey; +import webmvc.org.springframework.web.servlet.mvc.tobe.default_controller.ForwardController; -public class AnnotationHandlerMapping implements HandlerMapping{ +public class AnnotationHandlerMapping implements HandlerMapping { + private static final String DEFAULT_CONTROLLER_PACKAGE = + ForwardController.class.getPackage().getName(); private static final Logger log = LoggerFactory.getLogger(AnnotationHandlerMapping.class); private final Object[] basePackage; private final Map handlerExecutions; public AnnotationHandlerMapping(final Object... basePackage) { - this.basePackage = basePackage; + this.basePackage = Stream.of(basePackage, DEFAULT_CONTROLLER_PACKAGE).toArray(); this.handlerExecutions = new HashMap<>(); } diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerMapping.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/HandlerMapping.java similarity index 57% rename from mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerMapping.java rename to mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/HandlerMapping.java index d96b7f2bff..f620b77268 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerMapping.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/HandlerMapping.java @@ -1,6 +1,7 @@ -package webmvc.org.springframework.web.servlet.mvc.tobe; +package webmvc.org.springframework.web.servlet.mvc.tobe.handler_mapping; import jakarta.servlet.http.HttpServletRequest; +import webmvc.org.springframework.web.servlet.mvc.tobe.Handler; public interface HandlerMapping { diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerMappings.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/HandlerMappings.java similarity index 81% rename from mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerMappings.java rename to mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/HandlerMappings.java index 7dd1557627..d4b2469e62 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerMappings.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/HandlerMappings.java @@ -1,10 +1,12 @@ -package webmvc.org.springframework.web.servlet.mvc.tobe; +package webmvc.org.springframework.web.servlet.mvc.tobe.handler_mapping; import jakarta.servlet.http.HttpServletRequest; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; +import webmvc.org.springframework.web.servlet.mvc.tobe.Handler; +import webmvc.org.springframework.web.servlet.mvc.tobe.NotFoundHandler; public class HandlerMappings { 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/handler_mapping/AnnotationHandlerMappingTest.java similarity index 88% rename from mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/AnnotationHandlerMappingTest.java rename to mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/AnnotationHandlerMappingTest.java index f9bc8cbbd4..b252727c8c 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/handler_mapping/AnnotationHandlerMappingTest.java @@ -1,4 +1,4 @@ -package webmvc.org.springframework.web.servlet.mvc.tobe; +package webmvc.org.springframework.web.servlet.mvc.tobe.handler_mapping; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -9,6 +9,8 @@ import java.lang.reflect.InvocationTargetException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerExecution; +import webmvc.org.springframework.web.servlet.mvc.tobe.handler_mapping.AnnotationHandlerMapping; class AnnotationHandlerMappingTest { From 9ca3920ad5d22846b0d9be9752102aa308b62a8e Mon Sep 17 00:00:00 2001 From: hong-sile Date: Mon, 25 Sep 2023 16:24:52 +0900 Subject: [PATCH 11/18] =?UTF-8?q?feat:=20ManualHandlerMapping=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DispatcherServletInitializer.java | 3 +- .../com/techcourse/ManualHandlerMapping.java | 41 ------------------- .../com/techcourse/DispatcherServletTest.java | 3 +- .../servlet/mvc/tobe/DispatcherServlet.java | 2 + .../ForwardController.java | 2 +- 5 files changed, 5 insertions(+), 46 deletions(-) delete mode 100644 app/src/main/java/com/techcourse/ManualHandlerMapping.java rename mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/{ => default_controller}/ForwardController.java (91%) diff --git a/app/src/main/java/com/techcourse/DispatcherServletInitializer.java b/app/src/main/java/com/techcourse/DispatcherServletInitializer.java index 716f38a1d8..4f24da4b03 100644 --- a/app/src/main/java/com/techcourse/DispatcherServletInitializer.java +++ b/app/src/main/java/com/techcourse/DispatcherServletInitializer.java @@ -4,7 +4,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import web.org.springframework.web.WebApplicationInitializer; -import webmvc.org.springframework.web.servlet.mvc.tobe.AnnotationHandlerMapping; +import webmvc.org.springframework.web.servlet.mvc.tobe.handler_mapping.AnnotationHandlerMapping; import webmvc.org.springframework.web.servlet.mvc.tobe.DispatcherServlet; /** @@ -20,7 +20,6 @@ public class DispatcherServletInitializer implements WebApplicationInitializer { @Override public void onStartup(final ServletContext servletContext) { final var dispatcherServlet = new DispatcherServlet( - new ManualHandlerMapping(), new AnnotationHandlerMapping(getClass().getPackage().getName()) ); diff --git a/app/src/main/java/com/techcourse/ManualHandlerMapping.java b/app/src/main/java/com/techcourse/ManualHandlerMapping.java deleted file mode 100644 index e84b3fc033..0000000000 --- a/app/src/main/java/com/techcourse/ManualHandlerMapping.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.techcourse; - -import com.techcourse.controller.LoginController; -import com.techcourse.controller.LoginViewController; -import com.techcourse.controller.LogoutController; -import com.techcourse.controller.RegisterViewController; -import jakarta.servlet.http.HttpServletRequest; -import java.util.HashMap; -import java.util.Map; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import webmvc.org.springframework.web.servlet.mvc.asis.Controller; -import webmvc.org.springframework.web.servlet.mvc.asis.ForwardController; -import webmvc.org.springframework.web.servlet.mvc.tobe.Handler; -import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerMapping; - -public class ManualHandlerMapping implements HandlerMapping { - - private static final Logger log = LoggerFactory.getLogger(ManualHandlerMapping.class); - - private static final Map controllers = new HashMap<>(); - - @Override - public void initialize() { - controllers.put("/", new ForwardController("/index.jsp")); - controllers.put("/login", new LoginController()); - controllers.put("/login/view", new LoginViewController()); - controllers.put("/logout", new LogoutController()); - controllers.put("/register/view", new RegisterViewController()); - - log.info("Initialized Handler Mapping!"); - controllers.keySet() - .forEach(path -> log.info("Path : {}, Controller : {}", path, - controllers.get(path).getClass())); - } - - @Override - public Handler getHandler(final HttpServletRequest request) { - return controllers.get(request.getRequestURI()); - } -} diff --git a/app/src/test/java/com/techcourse/DispatcherServletTest.java b/app/src/test/java/com/techcourse/DispatcherServletTest.java index a6a1c1da0e..3d4b423d30 100644 --- a/app/src/test/java/com/techcourse/DispatcherServletTest.java +++ b/app/src/test/java/com/techcourse/DispatcherServletTest.java @@ -20,7 +20,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; -import webmvc.org.springframework.web.servlet.mvc.tobe.AnnotationHandlerMapping; +import webmvc.org.springframework.web.servlet.mvc.tobe.handler_mapping.AnnotationHandlerMapping; import webmvc.org.springframework.web.servlet.mvc.tobe.DispatcherServlet; class DispatcherServletTest { @@ -30,7 +30,6 @@ class DispatcherServletTest { @BeforeEach void setUp() { dispatcherServlet = new DispatcherServlet( - new ManualHandlerMapping(), new AnnotationHandlerMapping(getClass().getPackage().getName()) ); dispatcherServlet.init(); diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/DispatcherServlet.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/DispatcherServlet.java index 84cb83e95b..7ed386852a 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/DispatcherServlet.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/DispatcherServlet.java @@ -8,6 +8,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import webmvc.org.springframework.web.servlet.ModelAndView; +import webmvc.org.springframework.web.servlet.mvc.tobe.handler_mapping.HandlerMapping; +import webmvc.org.springframework.web.servlet.mvc.tobe.handler_mapping.HandlerMappings; public class DispatcherServlet extends HttpServlet { diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/ForwardController.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/default_controller/ForwardController.java similarity index 91% rename from mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/ForwardController.java rename to mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/default_controller/ForwardController.java index 207e89dc10..4933070b2c 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/ForwardController.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/default_controller/ForwardController.java @@ -1,4 +1,4 @@ -package webmvc.org.springframework.web.servlet.mvc.tobe; +package webmvc.org.springframework.web.servlet.mvc.tobe.default_controller; import context.org.springframework.stereotype.Controller; import jakarta.servlet.http.HttpServletRequest; From 84e4e3bef01ac59eb9bd36ad1e78510988fda3ec Mon Sep 17 00:00:00 2001 From: hong-sile Date: Mon, 25 Sep 2023 16:25:24 +0900 Subject: [PATCH 12/18] =?UTF-8?q?feat:=20=EB=A0=88=EA=B1=B0=EC=8B=9C=20Con?= =?UTF-8?q?troller=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/servlet/mvc/asis/Controller.java | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/Controller.java diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/Controller.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/Controller.java deleted file mode 100644 index 654c3b947a..0000000000 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/asis/Controller.java +++ /dev/null @@ -1,19 +0,0 @@ -package webmvc.org.springframework.web.servlet.mvc.asis; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import webmvc.org.springframework.web.servlet.ModelAndView; -import webmvc.org.springframework.web.servlet.mvc.tobe.Handler; -import webmvc.org.springframework.web.servlet.view.JspView; - -public interface Controller extends Handler { - - String execute(final HttpServletRequest req, final HttpServletResponse res) throws Exception; - - @Override - default ModelAndView handle(final HttpServletRequest request, - final HttpServletResponse response) throws Exception { - final String viewName = execute(request, response); - return new ModelAndView(new JspView(viewName)); - } -} From dbd8cfa64e5deb7917a48fc7340a5eb8c08c43a8 Mon Sep 17 00:00:00 2001 From: hong-sile Date: Mon, 25 Sep 2023 16:34:51 +0900 Subject: [PATCH 13/18] =?UTF-8?q?chore:=20tobe=EC=97=90=20=EC=9E=88?= =?UTF-8?q?=EB=8A=94=20=ED=81=B4=EB=9E=98=EC=8A=A4=EB=93=A4=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=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/{ => handler}/Handler.java | 2 +- .../web/servlet/mvc/tobe/{ => handler}/NotFoundHandler.java | 2 +- .../mvc/tobe/handler_mapping/AnnotationHandlerMapping.java | 4 +--- .../mvc/tobe/{ => handler_mapping}/HandlerExecution.java | 3 ++- .../servlet/mvc/tobe/{ => handler_mapping}/HandlerKey.java | 2 +- .../web/servlet/mvc/tobe/handler_mapping/HandlerMapping.java | 2 +- .../web/servlet/mvc/tobe/handler_mapping/HandlerMappings.java | 4 ++-- .../servlet/mvc/tobe/{ => handler}/NotFoundHandlerTest.java | 2 +- .../tobe/handler_mapping/AnnotationHandlerMappingTest.java | 2 -- 9 files changed, 10 insertions(+), 13 deletions(-) rename mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/{ => handler}/Handler.java (82%) rename mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/{ => handler}/NotFoundHandler.java (89%) rename mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/{ => handler_mapping}/HandlerExecution.java (86%) rename mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/{ => handler_mapping}/HandlerKey.java (92%) rename mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/{ => handler}/NotFoundHandlerTest.java (94%) diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/Handler.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler/Handler.java similarity index 82% rename from mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/Handler.java rename to mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler/Handler.java index cb238929f0..564954219f 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/Handler.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler/Handler.java @@ -1,4 +1,4 @@ -package webmvc.org.springframework.web.servlet.mvc.tobe; +package webmvc.org.springframework.web.servlet.mvc.tobe.handler; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/NotFoundHandler.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler/NotFoundHandler.java similarity index 89% rename from mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/NotFoundHandler.java rename to mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler/NotFoundHandler.java index 902a8f6a5e..2f68519111 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/NotFoundHandler.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler/NotFoundHandler.java @@ -1,4 +1,4 @@ -package webmvc.org.springframework.web.servlet.mvc.tobe; +package webmvc.org.springframework.web.servlet.mvc.tobe.handler; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/AnnotationHandlerMapping.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/AnnotationHandlerMapping.java index fb7a6c198d..9c19ef1fe2 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/AnnotationHandlerMapping.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/AnnotationHandlerMapping.java @@ -18,9 +18,7 @@ import web.org.springframework.web.bind.annotation.RequestMapping; import web.org.springframework.web.bind.annotation.RequestMethod; import webmvc.org.springframework.web.servlet.exception.RequestMethodNotValidException; -import webmvc.org.springframework.web.servlet.mvc.tobe.Handler; -import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerExecution; -import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerKey; +import webmvc.org.springframework.web.servlet.mvc.tobe.handler.Handler; import webmvc.org.springframework.web.servlet.mvc.tobe.default_controller.ForwardController; public class AnnotationHandlerMapping implements HandlerMapping { 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/handler_mapping/HandlerExecution.java similarity index 86% rename from mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerExecution.java rename to mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/HandlerExecution.java index f56da6da8f..ea75102ab2 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/handler_mapping/HandlerExecution.java @@ -1,10 +1,11 @@ -package webmvc.org.springframework.web.servlet.mvc.tobe; +package webmvc.org.springframework.web.servlet.mvc.tobe.handler_mapping; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.lang.reflect.Method; import webmvc.org.springframework.web.servlet.ModelAndView; import webmvc.org.springframework.web.servlet.exception.HandlerExecutionNotInitializeException; +import webmvc.org.springframework.web.servlet.mvc.tobe.handler.Handler; public class HandlerExecution implements Handler { 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/handler_mapping/HandlerKey.java similarity index 92% rename from mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/HandlerKey.java rename to mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/HandlerKey.java index 1de908117c..1e41dac9c6 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/handler_mapping/HandlerKey.java @@ -1,4 +1,4 @@ -package webmvc.org.springframework.web.servlet.mvc.tobe; +package webmvc.org.springframework.web.servlet.mvc.tobe.handler_mapping; import java.util.Objects; import web.org.springframework.web.bind.annotation.RequestMethod; diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/HandlerMapping.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/HandlerMapping.java index f620b77268..577f4ed18f 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/HandlerMapping.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/HandlerMapping.java @@ -1,7 +1,7 @@ package webmvc.org.springframework.web.servlet.mvc.tobe.handler_mapping; import jakarta.servlet.http.HttpServletRequest; -import webmvc.org.springframework.web.servlet.mvc.tobe.Handler; +import webmvc.org.springframework.web.servlet.mvc.tobe.handler.Handler; public interface HandlerMapping { diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/HandlerMappings.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/HandlerMappings.java index d4b2469e62..2d0b9391b6 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/HandlerMappings.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/HandlerMappings.java @@ -5,8 +5,8 @@ import java.util.List; import java.util.Objects; import java.util.stream.Collectors; -import webmvc.org.springframework.web.servlet.mvc.tobe.Handler; -import webmvc.org.springframework.web.servlet.mvc.tobe.NotFoundHandler; +import webmvc.org.springframework.web.servlet.mvc.tobe.handler.Handler; +import webmvc.org.springframework.web.servlet.mvc.tobe.handler.NotFoundHandler; public class HandlerMappings { diff --git a/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/NotFoundHandlerTest.java b/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler/NotFoundHandlerTest.java similarity index 94% rename from mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/NotFoundHandlerTest.java rename to mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler/NotFoundHandlerTest.java index 6f8b01ebee..5fd59ba63e 100644 --- a/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/NotFoundHandlerTest.java +++ b/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler/NotFoundHandlerTest.java @@ -1,4 +1,4 @@ -package webmvc.org.springframework.web.servlet.mvc.tobe; +package webmvc.org.springframework.web.servlet.mvc.tobe.handler; import static org.assertj.core.api.Assertions.assertThat; diff --git a/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/AnnotationHandlerMappingTest.java b/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/AnnotationHandlerMappingTest.java index b252727c8c..83d42e4a46 100644 --- a/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/AnnotationHandlerMappingTest.java +++ b/mvc/src/test/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/AnnotationHandlerMappingTest.java @@ -9,8 +9,6 @@ import java.lang.reflect.InvocationTargetException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import webmvc.org.springframework.web.servlet.mvc.tobe.HandlerExecution; -import webmvc.org.springframework.web.servlet.mvc.tobe.handler_mapping.AnnotationHandlerMapping; class AnnotationHandlerMappingTest { From ec903f83cda061e17935480bdf0d8d9182cfb0d9 Mon Sep 17 00:00:00 2001 From: hong-sile Date: Mon, 25 Sep 2023 17:03:37 +0900 Subject: [PATCH 14/18] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/test/java/com/techcourse/DispatcherServletTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/test/java/com/techcourse/DispatcherServletTest.java b/app/src/test/java/com/techcourse/DispatcherServletTest.java index 3d4b423d30..6965f003c2 100644 --- a/app/src/test/java/com/techcourse/DispatcherServletTest.java +++ b/app/src/test/java/com/techcourse/DispatcherServletTest.java @@ -20,8 +20,8 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; -import webmvc.org.springframework.web.servlet.mvc.tobe.handler_mapping.AnnotationHandlerMapping; import webmvc.org.springframework.web.servlet.mvc.tobe.DispatcherServlet; +import webmvc.org.springframework.web.servlet.mvc.tobe.handler_mapping.AnnotationHandlerMapping; class DispatcherServletTest { @@ -53,6 +53,7 @@ void show() throws ServletException, IOException { //given final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); final RequestDispatcher requestDispatcher = mock(RequestDispatcher.class); + when(request.getRequestURI()).thenReturn("/register/view"); when(request.getMethod()).thenReturn("GET"); when(request.getRequestDispatcher(argumentCaptor.capture())) .thenReturn(requestDispatcher); From d07a72f4189286f6c1f34343200062c169e5d820 Mon Sep 17 00:00:00 2001 From: hong-sile Date: Tue, 26 Sep 2023 12:54:25 +0900 Subject: [PATCH 15/18] =?UTF-8?q?feat:=20initialize=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EB=B6=84=EB=A6=AC=ED=95=B4=EC=84=9C,=20default=5Fc?= =?UTF-8?q?ontroller=EB=A5=BC=20=EB=8D=AE=EC=96=B4=EC=94=8C=EC=9D=84=20?= =?UTF-8?q?=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tobe/handler_mapping/AnnotationHandlerMapping.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/AnnotationHandlerMapping.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/AnnotationHandlerMapping.java index 9c19ef1fe2..c936c50ff5 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/AnnotationHandlerMapping.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/mvc/tobe/handler_mapping/AnnotationHandlerMapping.java @@ -18,8 +18,8 @@ import web.org.springframework.web.bind.annotation.RequestMapping; import web.org.springframework.web.bind.annotation.RequestMethod; import webmvc.org.springframework.web.servlet.exception.RequestMethodNotValidException; -import webmvc.org.springframework.web.servlet.mvc.tobe.handler.Handler; import webmvc.org.springframework.web.servlet.mvc.tobe.default_controller.ForwardController; +import webmvc.org.springframework.web.servlet.mvc.tobe.handler.Handler; public class AnnotationHandlerMapping implements HandlerMapping { @@ -31,14 +31,19 @@ public class AnnotationHandlerMapping implements HandlerMapping { private final Map handlerExecutions; public AnnotationHandlerMapping(final Object... basePackage) { - this.basePackage = Stream.of(basePackage, DEFAULT_CONTROLLER_PACKAGE).toArray(); + this.basePackage = basePackage; this.handlerExecutions = new HashMap<>(); + initializeByPackages(DEFAULT_CONTROLLER_PACKAGE); } @Override public void initialize() { log.info("Initialized AnnotationHandlerMapping!"); + initializeByPackages(basePackage); + } + + private void initializeByPackages(final Object... basePackage) { final Set> controllerClazz = new Reflections(basePackage) .getTypesAnnotatedWith(Controller.class); final Map handlerExecutions = controllerClazz From 761c041695a0958f338ca1cada2c52a74ff700c2 Mon Sep 17 00:00:00 2001 From: hong-sile Date: Tue, 26 Sep 2023 12:56:06 +0900 Subject: [PATCH 16/18] =?UTF-8?q?refactor:=20Object=20Mapper=EB=A5=BC=20st?= =?UTF-8?q?atic=20=EB=B3=80=EC=88=98=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/springframework/web/servlet/view/JsonView.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java b/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java index d5d5ae72e7..070751ddf6 100644 --- a/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java +++ b/mvc/src/main/java/webmvc/org/springframework/web/servlet/view/JsonView.java @@ -10,7 +10,7 @@ public class JsonView implements View { - private final ObjectMapper objectMapper = new ObjectMapper(); + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @Override public void render(final Map model, final HttpServletRequest request, @@ -22,8 +22,8 @@ public void render(final Map model, final HttpServletRequest request, private String convertModel(final Map model) throws JsonProcessingException { if (model.size() == 1) { - return objectMapper.writeValueAsString(model.values().toArray()[0]); + return OBJECT_MAPPER.writeValueAsString(model.values().toArray()[0]); } - return objectMapper.writeValueAsString(model); + return OBJECT_MAPPER.writeValueAsString(model); } } From 9bb17fd19817018ab08bcc95d90b0f885e2f21d1 Mon Sep 17 00:00:00 2001 From: hong-sile Date: Tue, 26 Sep 2023 17:33:16 +0900 Subject: [PATCH 17/18] =?UTF-8?q?feat:=20DIContainer=20step3=20=ED=95=99?= =?UTF-8?q?=EC=8A=B5=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=A7=84=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/di/stage3/context/DIContainer.java | 61 ++++++++++++++++++- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/study/src/test/java/di/stage3/context/DIContainer.java b/study/src/test/java/di/stage3/context/DIContainer.java index b62feb1ed3..e6e359c669 100644 --- a/study/src/test/java/di/stage3/context/DIContainer.java +++ b/study/src/test/java/di/stage3/context/DIContainer.java @@ -1,6 +1,11 @@ package di.stage3.context; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; /** * 스프링의 BeanFactory, ApplicationContext에 해당되는 클래스 @@ -10,11 +15,61 @@ class DIContainer { private final Set beans; public DIContainer(final Set> classes) { - this.beans = Set.of(); + this.beans = createBeans(classes); + setFields(beans); + } + + private void setFields(final Set beans) { + for (final Object bean : beans) { + final Field[] declaredFields = bean.getClass().getDeclaredFields(); + injectBeans(declaredFields, bean); + } + } + + private void injectBeans(final Field[] declaredFields, final Object bean) { + Arrays.stream(declaredFields) + .filter(field -> filterFieldIsNull(field, bean)) + .forEach(field -> injectBean(field, bean)); + } + + private boolean filterFieldIsNull(final Field field, final Object bean) { + try { + field.setAccessible(true); + return Objects.isNull(field.get(bean)); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private void injectBean(final Field field, final Object object) { + try { + field.set(object, getBean(field.getType())); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private Set createBeans(final Set> classes) { + return classes.stream() + .map(this::createDefaultObject) + .collect(Collectors.toSet()); + } + + private Object createDefaultObject(final Class clazz) { + try { + final Constructor constructor = clazz.getDeclaredConstructor(); + constructor.setAccessible(true); + return constructor.newInstance(); + } catch (final Exception e) { + throw new IllegalArgumentException(e); + } } @SuppressWarnings("unchecked") - public T getBean(final Class aClass) { - return null; + public T getBean(final Class clazz) { + return (T) beans.stream() + .filter(object -> clazz.isAssignableFrom(object.getClass())) + .findFirst() + .orElse(null); } } From b2aece51f44bb9c685d609cbcfb783f735dbea44 Mon Sep 17 00:00:00 2001 From: hong-sile Date: Tue, 26 Sep 2023 17:40:24 +0900 Subject: [PATCH 18/18] =?UTF-8?q?feat:=20DIContainer=20step=204=20?= =?UTF-8?q?=EC=A7=84=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stage4/annotations/ClassPathScanner.java | 6 +- .../di/stage4/annotations/DIContainer.java | 65 +++++++++++++++++-- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/study/src/test/java/di/stage4/annotations/ClassPathScanner.java b/study/src/test/java/di/stage4/annotations/ClassPathScanner.java index 9dab1fd9c4..12073ce3b5 100644 --- a/study/src/test/java/di/stage4/annotations/ClassPathScanner.java +++ b/study/src/test/java/di/stage4/annotations/ClassPathScanner.java @@ -1,10 +1,14 @@ package di.stage4.annotations; import java.util.Set; +import org.reflections.Reflections; public class ClassPathScanner { public static Set> getAllClassesInPackage(final String packageName) { - return null; + final Set> classes = new Reflections(packageName) + .getTypesAnnotatedWith(Repository.class); + classes.addAll(new Reflections(packageName).getTypesAnnotatedWith(Service.class)); + return classes; } } diff --git a/study/src/test/java/di/stage4/annotations/DIContainer.java b/study/src/test/java/di/stage4/annotations/DIContainer.java index 9248ecad7e..0fec7380e6 100644 --- a/study/src/test/java/di/stage4/annotations/DIContainer.java +++ b/study/src/test/java/di/stage4/annotations/DIContainer.java @@ -1,6 +1,11 @@ package di.stage4.annotations; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; /** * 스프링의 BeanFactory, ApplicationContext에 해당되는 클래스 @@ -10,15 +15,67 @@ class DIContainer { private final Set beans; public DIContainer(final Set> classes) { - this.beans = Set.of(); + this.beans = createBeans(classes); + setFields(beans); } public static DIContainer createContainerForPackage(final String rootPackageName) { - return null; + final Set> classes = ClassPathScanner.getAllClassesInPackage(rootPackageName); + return new DIContainer(classes); + } + + private void setFields(final Set beans) { + for (final Object bean : beans) { + final Field[] declaredFields = bean.getClass().getDeclaredFields(); + injectBeans(declaredFields, bean); + } + } + + private void injectBeans(final Field[] declaredFields, final Object bean) { + Arrays.stream(declaredFields) + .filter(field -> filterFieldIsNull(field, bean)) + .filter(field -> field.isAnnotationPresent(Inject.class)) + .forEach(field -> injectBean(field, bean)); + } + + private boolean filterFieldIsNull(final Field field, final Object bean) { + try { + field.setAccessible(true); + return Objects.isNull(field.get(bean)); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private void injectBean(final Field field, final Object object) { + try { + field.set(object, getBean(field.getType())); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private Set createBeans(final Set> classes) { + return classes.stream() + .map(this::createDefaultObject) + .collect(Collectors.toSet()); + } + + private Object createDefaultObject(final Class clazz) { + try { + final Constructor constructor = clazz.getDeclaredConstructor(); + constructor.setAccessible(true); + return constructor.newInstance(); + } catch (final Exception e) { + throw new IllegalArgumentException(e); + } } @SuppressWarnings("unchecked") - public T getBean(final Class aClass) { - return null; + public T getBean(final Class clazz) { + return (T) beans.stream() + .filter(object -> clazz.isAssignableFrom(object.getClass())) + .findFirst() + .orElse(null); } }