diff --git a/1-0-networking-and-http/1-0-0-hello-network-socket/src/main/java/com/bobocode/net/client/ClientUtil.java b/1-0-networking-and-http/1-0-0-hello-network-socket/src/main/java/com/bobocode/net/client/ClientUtil.java index e2cdac5..a622a8b 100644 --- a/1-0-networking-and-http/1-0-0-hello-network-socket/src/main/java/com/bobocode/net/client/ClientUtil.java +++ b/1-0-networking-and-http/1-0-0-hello-network-socket/src/main/java/com/bobocode/net/client/ClientUtil.java @@ -24,7 +24,7 @@ private ClientUtil() { */ @SneakyThrows public static Socket openSocket(String host, int port) { - throw new ExerciseNotCompletedException(); // todo: implement according to javadoc and verify by ClientUtilTest + return new Socket(host, port); } /** @@ -62,6 +62,8 @@ public static String readMessage(BufferedReader reader) { */ @SneakyThrows public static void writeToSocket(String message, Socket socket) { - throw new ExerciseNotCompletedException(); // todo: implement according to javadoc and verify by ClientUtilTest + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); + writer.write(message); + writer.flush(); } } diff --git a/1-0-networking-and-http/1-0-0-hello-network-socket/src/main/java/com/bobocode/net/server/ServerUtil.java b/1-0-networking-and-http/1-0-0-hello-network-socket/src/main/java/com/bobocode/net/server/ServerUtil.java index 3778579..239c627 100644 --- a/1-0-networking-and-http/1-0-0-hello-network-socket/src/main/java/com/bobocode/net/server/ServerUtil.java +++ b/1-0-networking-and-http/1-0-0-hello-network-socket/src/main/java/com/bobocode/net/server/ServerUtil.java @@ -41,7 +41,7 @@ public static String getLocalHost() { */ @SneakyThrows public static ServerSocket createServerSocket(int port) { - throw new ExerciseNotCompletedException(); // todo: implement according to javadoc and verify by ServerUtilTest + return new ServerSocket(port); } /** @@ -52,7 +52,7 @@ public static ServerSocket createServerSocket(int port) { */ @SneakyThrows public static Socket acceptClientSocket(ServerSocket serverSocket) { - throw new ExerciseNotCompletedException(); // todo: implement according to javadoc and verify by ServerUtilTest + return serverSocket.accept(); } /** @@ -66,7 +66,8 @@ public static Socket acceptClientSocket(ServerSocket serverSocket) { */ @SneakyThrows public static String readMessageFromSocket(Socket socket) { - throw new ExerciseNotCompletedException(); // todo: implement according to javadoc and verify by ServerUtilTest + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); + return bufferedReader.readLine(); } /** diff --git a/2-0-servlet-api/2-0-1-hello-servlet-api/src/main/java/com/bobocode/servlet/DateServlet.java b/2-0-servlet-api/2-0-1-hello-servlet-api/src/main/java/com/bobocode/servlet/DateServlet.java new file mode 100644 index 0000000..959d3c5 --- /dev/null +++ b/2-0-servlet-api/2-0-1-hello-servlet-api/src/main/java/com/bobocode/servlet/DateServlet.java @@ -0,0 +1,21 @@ +package com.bobocode.servlet; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.time.LocalDate; + +@WebServlet("/date") +public class DateServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + var writer = resp.getWriter(); + var date = LocalDate.now(); + writer.println(date); + } +} diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/ApplicationConfig.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/ApplicationConfig.java index f7ebf38..af3e939 100644 --- a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/ApplicationConfig.java +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/config/ApplicationConfig.java @@ -1,16 +1,40 @@ package com.bobocode.config; import com.bobocode.TestDataGenerator; +import com.bobocode.dao.AccountDao; +import com.bobocode.dao.FakeAccountDao; +import com.bobocode.model.Account; +import com.bobocode.service.AccountService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +import java.util.List; /** * This class specifies application context configuration. It tells Spring to scan "dao" and "service" packages in order - * to find and create instances for {@link com.bobocode.dao.FakeAccountDao} and - * {@link com.bobocode.service.AccountService}. + * to find and create instances for {@link FakeAccountDao} and + * {@link AccountService}. *

* It also explicitly configures a bean of {@link TestDataGenerator} called "dataGenerator". This beans will be injected - * into {@link com.bobocode.dao.FakeAccountDao} in order to generate some fake accounts. + * into {@link FakeAccountDao} in order to generate some fake accounts. */ +@Configuration +@ComponentScan(basePackages = {"com.bobocode.dao", "com.bobocode.service"}) public class ApplicationConfig { - // todo: configure application context according to javadoc by following tests in ApplicationConfigTest - // todo: verify final implementation by running ApplicationContextTest + @Bean + public TestDataGenerator dataGenerator() { + return new TestDataGenerator(); + } + + @Bean + public AccountDao accountDao() { + return new FakeAccountDao(dataGenerator()); + } + + @Bean + public AccountService accountService() { + return new AccountService(accountDao()); + } + } diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/FakeAccountDao.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/FakeAccountDao.java index bae7264..988a90b 100644 --- a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/FakeAccountDao.java +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/dao/FakeAccountDao.java @@ -2,6 +2,8 @@ import com.bobocode.TestDataGenerator; import com.bobocode.model.Account; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import java.util.List; import java.util.stream.Stream; @@ -16,9 +18,11 @@ * Its bean is called "accountDao". And it uses constructor with explicit autowired annotation in order to inject * {@link TestDataGenerator} instance. */ +@Component("accountDao") public class FakeAccountDao implements AccountDao { private List accounts; + @Autowired public FakeAccountDao(TestDataGenerator testDataGenerator) { this.accounts = Stream.generate(testDataGenerator::generateAccount) .limit(20) diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java index a46dfd2..a17cf03 100644 --- a/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/main/java/com/bobocode/service/AccountService.java @@ -2,6 +2,8 @@ import com.bobocode.dao.AccountDao; import com.bobocode.model.Account; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import static java.util.Comparator.comparing; @@ -12,6 +14,7 @@ * Since it's a service that should be added to the application context, it is marked as Spring service. It order to get * {@link AccountDao} instances, it uses implicit constructor-based injection. */ +@Service public class AccountService { private final AccountDao accountDao; diff --git a/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationContextTest.java b/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationContextTest.java index a0aff88..34026b1 100644 --- a/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationContextTest.java +++ b/3-0-spring-framework/3-0-0-hello-spring-framework/src/test/java/com/bobocode/ApplicationContextTest.java @@ -32,7 +32,6 @@ static class TestConfig { @DisplayName("DataGenerator has only one bean") void dataGeneratorHasOnlyOneBean() { Map testDataGeneratorMap = applicationContext.getBeansOfType(TestDataGenerator.class); - assertThat(testDataGeneratorMap.size()).isEqualTo(1); } diff --git a/3-0-spring-framework/3-0-1-hello-spring-mvc/src/main/java/com/bobocode/mvc/api/NoteRestController.java b/3-0-spring-framework/3-0-1-hello-spring-mvc/src/main/java/com/bobocode/mvc/api/NoteRestController.java index 95d9ed6..0a195c3 100644 --- a/3-0-spring-framework/3-0-1-hello-spring-mvc/src/main/java/com/bobocode/mvc/api/NoteRestController.java +++ b/3-0-spring-framework/3-0-1-hello-spring-mvc/src/main/java/com/bobocode/mvc/api/NoteRestController.java @@ -1,7 +1,15 @@ package com.bobocode.mvc.api; import com.bobocode.mvc.data.Notes; +import com.bobocode.mvc.model.Note; import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; /** * This controller provides a very simple REST API for Notes. It implements two endpoints that allow you to add @@ -19,8 +27,21 @@ * via models, like in {@link com.bobocode.mvc.controller.NoteController} */ @RequiredArgsConstructor +@RestController +@RequestMapping("/api/notes") public class NoteRestController { private final Notes notes; - // TODO: implement controller methods according to the javadoc verify your impl using NoteRestControllerTest + @GetMapping() + public List getNote() { + return notes.getAll(); + } + + @PostMapping + public void addNote(@RequestBody Note note) { + if(note.getId() == null) { + + } + notes.add(note); + } } diff --git a/3-0-spring-framework/3-0-1-hello-spring-mvc/src/main/java/com/bobocode/mvc/api/api-notes.http b/3-0-spring-framework/3-0-1-hello-spring-mvc/src/main/java/com/bobocode/mvc/api/api-notes.http new file mode 100644 index 0000000..b307f2e --- /dev/null +++ b/3-0-spring-framework/3-0-1-hello-spring-mvc/src/main/java/com/bobocode/mvc/api/api-notes.http @@ -0,0 +1,11 @@ + +GET http://localhost:8080/api/notes +### + +POST http://localhost:8080/api/notes +Content-Type: application/json + +{ + "title": "New Note", + "text": "This is a new note." +} \ No newline at end of file diff --git a/3-0-spring-framework/3-0-1-hello-spring-mvc/src/main/java/com/bobocode/mvc/controller/NoteController.java b/3-0-spring-framework/3-0-1-hello-spring-mvc/src/main/java/com/bobocode/mvc/controller/NoteController.java index 3f9d528..16f50e0 100644 --- a/3-0-spring-framework/3-0-1-hello-spring-mvc/src/main/java/com/bobocode/mvc/controller/NoteController.java +++ b/3-0-spring-framework/3-0-1-hello-spring-mvc/src/main/java/com/bobocode/mvc/controller/NoteController.java @@ -1,7 +1,15 @@ package com.bobocode.mvc.controller; import com.bobocode.mvc.data.Notes; +import com.bobocode.mvc.model.Note; import lombok.RequiredArgsConstructor; +import org.springframework.boot.Banner; +import org.springframework.stereotype.Controller; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.ui.Model; /** * {@link NoteController} is a typical controller that powers Spring MVC Notes application. This application provides @@ -10,7 +18,7 @@ * is already provided as a field of class {@link Notes}. The base URL is `/notes`. *

* This controller handles the HTTP GET request that should list all notes. In order to do that, it fetches the list - * of notes, adds that list as an attribute to the {@link org.springframework.ui.Model}, and returns a corresponding view. + * of notes, adds that list as an attribute to the {@link Model}, and returns a corresponding view. * The view (which is Thymeleaf HTML template) expects to receive an attribute called `noteList`. * In classical Spring MVC, controller methods return a string value which stores a view name. * A {@link org.springframework.web.servlet.ViewResolver} is already configured to look for an HTML template in @@ -27,9 +35,22 @@ * the same controller will look like {@link com.bobocode.mvc.api.NoteRestController} */ @RequiredArgsConstructor +@Controller +@RequestMapping("/notes") public class NoteController { private final Notes notes; - // TODO: implement controller methods according to the javadoc and verify your impl using NoteControllerTest + + @GetMapping() + public String getNotes(Model model){ + model.addAttribute("noteList", notes.getAll()); + return "notes"; + } + + @PostMapping + public String addNote(Note note){ + notes.add(note); + return "redirect:/notes"; + } } diff --git a/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/main/java/com/bobocode/config/RootConfig.java b/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/main/java/com/bobocode/config/RootConfig.java index 6536634..1e33cc6 100644 --- a/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/main/java/com/bobocode/config/RootConfig.java +++ b/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/main/java/com/bobocode/config/RootConfig.java @@ -1,8 +1,10 @@ package com.bobocode.config; +import net.bytebuddy.implementation.bind.annotation.IgnoreForBinding; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; import org.springframework.stereotype.Controller; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @@ -15,5 +17,18 @@ * todo: enable component scanning for all packages in "com.bobocode" * todo: ignore all web related config and beans (ignore @{@link Controller}, ignore {@link EnableWebMvc}) using exclude filter */ +@Configuration +@ComponentScan(basePackages = "com.bobocode", + excludeFilters = { + @Filter( + type = FilterType.ANNOTATION, + classes = EnableWebMvc.class + ), + @Filter( + type = FilterType.ANNOTATION, + classes = Controller.class + ) + }) public class RootConfig { + } diff --git a/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/main/java/com/bobocode/config/WebAppInitializer.java b/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/main/java/com/bobocode/config/WebAppInitializer.java index ee23400..9f001de 100644 --- a/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/main/java/com/bobocode/config/WebAppInitializer.java +++ b/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/main/java/com/bobocode/config/WebAppInitializer.java @@ -1,6 +1,5 @@ package com.bobocode.config; -import com.bobocode.util.ExerciseNotCompletedException; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; /** @@ -9,16 +8,16 @@ public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class[] getRootConfigClasses() { - throw new ExerciseNotCompletedException(); //todo: use {@link RootConfig} as root application config class + return new Class[]{RootConfig.class}; } @Override protected Class[] getServletConfigClasses() { - throw new ExerciseNotCompletedException(); //todo: use {@link WebConfig} as ServletConfig class + return new Class[]{WebConfig.class}; } @Override protected String[] getServletMappings() { - throw new ExerciseNotCompletedException(); //todo: provide default servlet mapping ("/") + return new String[]{"/"}; } } diff --git a/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/main/java/com/bobocode/config/WebConfig.java b/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/main/java/com/bobocode/config/WebConfig.java index 66d3a84..e3f3815 100644 --- a/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/main/java/com/bobocode/config/WebConfig.java +++ b/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/main/java/com/bobocode/config/WebConfig.java @@ -14,5 +14,8 @@ * todo: enable component scanning for package "web" */ +@Configuration +@ComponentScan(basePackages = "com.bobocode.web") +@EnableWebMvc public class WebConfig { } diff --git a/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/main/java/com/bobocode/web/controller/WelcomeController.java b/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/main/java/com/bobocode/web/controller/WelcomeController.java index 77392cc..12dc892 100644 --- a/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/main/java/com/bobocode/web/controller/WelcomeController.java +++ b/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/main/java/com/bobocode/web/controller/WelcomeController.java @@ -1,5 +1,9 @@ package com.bobocode.web.controller; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; + /** * Welcome controller that consists of one method that handles get request to "/welcome" and respond with a message. *

@@ -8,8 +12,11 @@ * todo: tell Spring that {@link WelcomeController#welcome()} method provides response body without view */ +@Controller public class WelcomeController { + @GetMapping("/welcome") + @ResponseBody public String welcome() { return "Welcome to Spring MVC!"; } diff --git a/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/test/java/com/bobocode/WebAppConfigurationTest.java b/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/test/java/com/bobocode/WebAppConfigurationTest.java index 54710ed..b21b0fa 100644 --- a/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/test/java/com/bobocode/WebAppConfigurationTest.java +++ b/3-0-spring-framework/3-1-1-dispatcher-servlet-initializer/src/test/java/com/bobocode/WebAppConfigurationTest.java @@ -13,6 +13,8 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -170,6 +172,6 @@ void welcomeControllerMethodIsMarkedAsResponseBody() throws NoSuchMethodExceptio } private List getFilteredClasses(Filter[] filters) { - return Stream.of(filters).flatMap(filter -> Stream.of(filter.value())).collect(Collectors.toList()); + return Stream.of(filters).flatMap(filter -> Stream.of(filter.classes())).collect(Collectors.toList()); } } diff --git a/3-0-spring-framework/3-2-1-account-rest-api/src/main/java/com/bobocode/config/RootConfig.java b/3-0-spring-framework/3-2-1-account-rest-api/src/main/java/com/bobocode/config/RootConfig.java index c5d1a6d..7fc5222 100644 --- a/3-0-spring-framework/3-2-1-account-rest-api/src/main/java/com/bobocode/config/RootConfig.java +++ b/3-0-spring-framework/3-2-1-account-rest-api/src/main/java/com/bobocode/config/RootConfig.java @@ -1,5 +1,8 @@ package com.bobocode.config; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; import org.springframework.stereotype.Controller; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @@ -10,5 +13,17 @@ * todo: 2. Enable component scanning for all packages in "com.bobocode" using annotation property "basePackages" * todo: 3. Exclude web related config and beans (ignore @{@link Controller}, ignore {@link EnableWebMvc}) */ +@Configuration +@ComponentScan(basePackages = "com.bobocode", + excludeFilters = { + @ComponentScan.Filter( + type = FilterType.ANNOTATION, + classes = Controller.class + ), + @ComponentScan.Filter( + type = FilterType.ANNOTATION, + classes = EnableWebMvc.class + ) + }) public class RootConfig { } diff --git a/3-0-spring-framework/3-2-1-account-rest-api/src/main/java/com/bobocode/config/WebConfig.java b/3-0-spring-framework/3-2-1-account-rest-api/src/main/java/com/bobocode/config/WebConfig.java index 1197302..5652966 100644 --- a/3-0-spring-framework/3-2-1-account-rest-api/src/main/java/com/bobocode/config/WebConfig.java +++ b/3-0-spring-framework/3-2-1-account-rest-api/src/main/java/com/bobocode/config/WebConfig.java @@ -1,5 +1,9 @@ package com.bobocode.config; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + /** * This class provides web (servlet) related configuration. *

@@ -7,5 +11,8 @@ * todo: 2. Enable web mvc using annotation * todo: 3. Enable component scanning for package "web" using annotation value */ +@Configuration +@EnableWebMvc +@ComponentScan(basePackages = "com.bobocode.web") public class WebConfig { } diff --git a/3-0-spring-framework/3-2-1-account-rest-api/src/main/java/com/bobocode/dao/impl/InMemoryAccountDao.java b/3-0-spring-framework/3-2-1-account-rest-api/src/main/java/com/bobocode/dao/impl/InMemoryAccountDao.java index 5620d5b..d8f76d8 100644 --- a/3-0-spring-framework/3-2-1-account-rest-api/src/main/java/com/bobocode/dao/impl/InMemoryAccountDao.java +++ b/3-0-spring-framework/3-2-1-account-rest-api/src/main/java/com/bobocode/dao/impl/InMemoryAccountDao.java @@ -3,6 +3,9 @@ import com.bobocode.dao.AccountDao; import com.bobocode.exception.EntityNotFountException; import com.bobocode.model.Account; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.HashMap; @@ -10,10 +13,11 @@ import java.util.Map; /** - * {@link AccountDao} implementation that is based on {@link java.util.HashMap}. + * {@link AccountDao} implementation that is based on {@link HashMap}. *

* todo: 1. Configure a component with name "accountDao" */ +@Component("accountDao") public class InMemoryAccountDao implements AccountDao { private Map accountMap = new HashMap<>(); private long idSequence = 1L; diff --git a/3-0-spring-framework/3-2-1-account-rest-api/src/main/java/com/bobocode/web/controller/AccountRestController.java b/3-0-spring-framework/3-2-1-account-rest-api/src/main/java/com/bobocode/web/controller/AccountRestController.java index 84fb818..6ae178e 100644 --- a/3-0-spring-framework/3-2-1-account-rest-api/src/main/java/com/bobocode/web/controller/AccountRestController.java +++ b/3-0-spring-framework/3-2-1-account-rest-api/src/main/java/com/bobocode/web/controller/AccountRestController.java @@ -1,6 +1,24 @@ package com.bobocode.web.controller; import com.bobocode.dao.AccountDao; +import com.bobocode.dao.impl.InMemoryAccountDao; +import com.bobocode.model.Account; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.OK; /** *

@@ -16,6 +34,48 @@ * todo: 7. Implement method that handles DELETE request with id as path variable removes an account by id * todo: Configure HTTP response status code 204 - NO CONTENT */ -public class AccountRestController { +@RestController() +@RequestMapping("/accounts") +public class AccountRestController implements AccountDao { + protected AccountDao accountDao = new InMemoryAccountDao(); + + + public AccountRestController(AccountDao accountDao) { + this.accountDao = accountDao; + } + + @Override + @GetMapping + public List findAll( ) { + return accountDao.findAll(); + } + + @Override + @GetMapping("/{id}") + public Account findById(@PathVariable long id) { + Account account = accountDao.findById(id); + ResponseEntity.status(OK).body(account); + return account; + } + + @Override + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public Account save(@RequestBody Account account) { + return accountDao.save(account); + } + + @Override + @DeleteMapping("/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void remove(Account account) { + accountDao.remove(account); + } + + @PutMapping("/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void update(@RequestBody Account account) { + accountDao.save(account); + } } diff --git a/3-0-spring-framework/3-2-1-account-rest-api/src/test/java/com/bobocode/WebAppConfigurationTest.java b/3-0-spring-framework/3-2-1-account-rest-api/src/test/java/com/bobocode/WebAppConfigurationTest.java index 6b5640d..6ed75cc 100644 --- a/3-0-spring-framework/3-2-1-account-rest-api/src/test/java/com/bobocode/WebAppConfigurationTest.java +++ b/3-0-spring-framework/3-2-1-account-rest-api/src/test/java/com/bobocode/WebAppConfigurationTest.java @@ -61,7 +61,7 @@ void webConfigClassIsConfiguredProperly() { } private List getFilteredClasses(Filter[] filters) { - return Stream.of(filters).flatMap(filter -> Stream.of(filter.value())).collect(Collectors.toList()); + return Stream.of(filters).flatMap(filter -> Stream.of(filter.classes())).collect(Collectors.toList()); } @Test diff --git a/3-0-spring-framework/3-3-0-enable-string-trimming/src/main/java/com/bobocode/StringTrimmingConfiguration.java b/3-0-spring-framework/3-3-0-enable-string-trimming/src/main/java/com/bobocode/StringTrimmingConfiguration.java new file mode 100644 index 0000000..1e25b5a --- /dev/null +++ b/3-0-spring-framework/3-3-0-enable-string-trimming/src/main/java/com/bobocode/StringTrimmingConfiguration.java @@ -0,0 +1,12 @@ +package com.bobocode; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +public class StringTrimmingConfiguration { + + @Bean + public TrimmedAnnotationBeanPostProcessor postProcessorBean(){ + return new TrimmedAnnotationBeanPostProcessor(); + } +} diff --git a/3-0-spring-framework/3-3-0-enable-string-trimming/src/main/java/com/bobocode/TrimmedAnnotationBeanPostProcessor.java b/3-0-spring-framework/3-3-0-enable-string-trimming/src/main/java/com/bobocode/TrimmedAnnotationBeanPostProcessor.java index ee1d441..ed37724 100644 --- a/3-0-spring-framework/3-3-0-enable-string-trimming/src/main/java/com/bobocode/TrimmedAnnotationBeanPostProcessor.java +++ b/3-0-spring-framework/3-3-0-enable-string-trimming/src/main/java/com/bobocode/TrimmedAnnotationBeanPostProcessor.java @@ -1,21 +1,57 @@ package com.bobocode; import com.bobocode.annotation.Trimmed; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.cglib.proxy.Enhancer; +import org.springframework.cglib.proxy.MethodInterceptor; +import org.springframework.cglib.proxy.MethodProxy; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; +import java.lang.reflect.Method; + /** * This is processor class implements {@link BeanPostProcessor}, looks for a beans where method parameters are marked with * {@link Trimmed} annotation, creates proxy of them, overrides methods and trims all {@link String} arguments marked with * {@link Trimmed}. For example if there is a string " Java " as an input parameter it has to be automatically trimmed to "Java" * if parameter is marked with {@link Trimmed} annotation. *

- * + *

* Note! This bean is not marked as a {@link Component} to avoid automatic scanning, instead it should be created in * {@link StringTrimmingConfiguration} class which can be imported to a {@link Configuration} class by annotation * {@link EnableStringTrimming} */ -public class TrimmedAnnotationBeanPostProcessor { -//todo: Implement TrimmedAnnotationBeanPostProcessor according to javadoc +public class TrimmedAnnotationBeanPostProcessor implements BeanPostProcessor { + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + Class beanClass = bean.getClass(); + if(beanClass.isAnnotationPresent(Trimmed.class)) { + System.out.println(bean.getClass()); + return createLoggingProxy(beanClass); + } + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + Class beanClass = bean.getClass(); + if(beanClass.isAnnotationPresent(Trimmed.class)) { + System.out.println(bean.getClass()); + return createLoggingProxy(beanClass); + } + return bean; + } + + public Object createLoggingProxy(Class beanType) { + var enhancer = new Enhancer(); + enhancer.setSuperclass(beanType); + enhancer.setInterfaces(beanType.getInterfaces()); + + MethodInterceptor methodInterceptor = (Object obj, Method method, Object[] args, MethodProxy proxy) -> { + return null; + }; + return beanType.cast(enhancer.create()); + } + } diff --git a/3-0-spring-framework/3-3-0-enable-string-trimming/src/main/java/com/bobocode/annotation/EnableStringTrimming.java b/3-0-spring-framework/3-3-0-enable-string-trimming/src/main/java/com/bobocode/annotation/EnableStringTrimming.java index 8c06d65..b04911f 100644 --- a/3-0-spring-framework/3-3-0-enable-string-trimming/src/main/java/com/bobocode/annotation/EnableStringTrimming.java +++ b/3-0-spring-framework/3-3-0-enable-string-trimming/src/main/java/com/bobocode/annotation/EnableStringTrimming.java @@ -1,8 +1,18 @@ package com.bobocode.annotation; +import com.bobocode.StringTrimmingConfiguration; +import org.springframework.context.annotation.Import; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + /** * Annotation that can be placed on configuration class to import {@link StringTrimmingConfiguration} */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Import(StringTrimmingConfiguration.class) public @interface EnableStringTrimming { -//todo: Implement EnableStringTrimming annotation according to javadoc }