diff --git a/account-jsp/src/main/java/com/bobocode/config/AccountWebAppInitializer.java b/account-jsp/src/main/java/com/bobocode/config/AccountWebAppInitializer.java index 3b0ce87..c50ab59 100644 --- a/account-jsp/src/main/java/com/bobocode/config/AccountWebAppInitializer.java +++ b/account-jsp/src/main/java/com/bobocode/config/AccountWebAppInitializer.java @@ -12,16 +12,17 @@ public class AccountWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class[] getRootConfigClasses() { - throw new UnsupportedOperationException("It's your job to implement this method!"); + return new Class[]{RootConfig.class}; } @Override protected Class[] getServletConfigClasses() { - throw new UnsupportedOperationException("It's your job to implement this method!"); + return new Class[]{WebConfig.class}; } @Override protected String[] getServletMappings() { - throw new UnsupportedOperationException("It's your job to implement this method!"); + return new String[]{"/"}; } } + diff --git a/account-jsp/src/main/java/com/bobocode/config/RootConfig.java b/account-jsp/src/main/java/com/bobocode/config/RootConfig.java index 27e98f6..043ea11 100644 --- a/account-jsp/src/main/java/com/bobocode/config/RootConfig.java +++ b/account-jsp/src/main/java/com/bobocode/config/RootConfig.java @@ -1,6 +1,10 @@ package com.bobocode.config; import com.bobocode.TestDataGenerator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Controller; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @@ -12,5 +16,12 @@ * todo: 3. Exclude web related config and beans (ignore @{@link Controller}, ignore {@link EnableWebMvc}) * todo: 4. Configure {@link TestDataGenerator} bean with name "dataGenerator" (don't specify name explicitly) */ +@Configuration +@ComponentScan(basePackages = "com.bobocode", excludeFilters = {@Filter(EnableWebMvc.class), @Filter(Controller.class)}) public class RootConfig { + @Bean + public TestDataGenerator dataGenerator() { + return new TestDataGenerator(); + } } + diff --git a/account-jsp/src/main/java/com/bobocode/config/WebConfig.java b/account-jsp/src/main/java/com/bobocode/config/WebConfig.java index edf8c8a..d40a7cc 100644 --- a/account-jsp/src/main/java/com/bobocode/config/WebConfig.java +++ b/account-jsp/src/main/java/com/bobocode/config/WebConfig.java @@ -1,5 +1,12 @@ package com.bobocode.config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.ViewResolver; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.view.InternalResourceViewResolver; + /** * This class provides web (servlet) related configuration. *

@@ -8,6 +15,17 @@ * todo: 3. Enable component scanning for package "web" using annotation value * todo: 4. Configure JPS internal view resolver with prefix = "/WEB-INF/views/" and suffix ".jsp" */ +@Configuration +@ComponentScan("com.bobocode.web") +@EnableWebMvc public class WebConfig { + @Bean + public ViewResolver viewResolver() { + InternalResourceViewResolver resolver = new InternalResourceViewResolver(); + resolver.setPrefix("/WEB-INF/views/"); + resolver.setSuffix(".jsp"); + return resolver; + } } + diff --git a/account-jsp/src/main/java/com/bobocode/web/controller/AccountController.java b/account-jsp/src/main/java/com/bobocode/web/controller/AccountController.java index f512655..4e9db47 100644 --- a/account-jsp/src/main/java/com/bobocode/web/controller/AccountController.java +++ b/account-jsp/src/main/java/com/bobocode/web/controller/AccountController.java @@ -2,6 +2,17 @@ import com.bobocode.TestDataGenerator; import com.bobocode.model.Account; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toList; /** * This controller provides endpoint that generates a list of {@link Account} and passes it to the view. @@ -13,6 +24,17 @@ * todo: 5. Provide a default value "10" for parameter "size" * todo: 6. Pass the list of accounts to the view using model attribute with name "accountList" */ +@Controller +@RequestMapping("/accounts") public class AccountController { + @Autowired + private TestDataGenerator dataGenerator; + @GetMapping + public String getAccounts(@RequestParam(name = "size", defaultValue = "10") int size, Model model) { + List accounts = Stream.generate(dataGenerator::generateAccount).limit(size).collect(toList()); + model.addAttribute("accountList", accounts); + return "accounts"; + } } + diff --git a/account-jsp/src/main/java/com/bobocode/web/controller/WelcomeController.java b/account-jsp/src/main/java/com/bobocode/web/controller/WelcomeController.java index b78e0e5..7854a6b 100644 --- a/account-jsp/src/main/java/com/bobocode/web/controller/WelcomeController.java +++ b/account-jsp/src/main/java/com/bobocode/web/controller/WelcomeController.java @@ -1,5 +1,8 @@ package com.bobocode.web.controller; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + /** * Welcome controller that consists of one method that handles get request to "/" and "/welcome" and respond with a message. *

@@ -7,6 +10,13 @@ * todo: 2. Configure HTTP GET mapping "/" and "/welcome" for method {@link WelcomeController#welcome()} * todo: 3. Forward the request to "welcome.jsp" view */ +@Controller public class WelcomeController { + @GetMapping({"/", "/welcome"}) + public String welcome() { + return "welcome"; + } + } + diff --git a/account-rest-api/src/main/java/com/bobocode/config/RootConfig.java b/account-rest-api/src/main/java/com/bobocode/config/RootConfig.java index c5d1a6d..fe8f56e 100644 --- a/account-rest-api/src/main/java/com/bobocode/config/RootConfig.java +++ b/account-rest-api/src/main/java/com/bobocode/config/RootConfig.java @@ -1,5 +1,9 @@ package com.bobocode.config; +import com.bobocode.TestDataGenerator; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Controller; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @@ -10,5 +14,8 @@ * 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 = {@Filter(EnableWebMvc.class), @Filter(Controller.class)}) public class RootConfig { } + diff --git a/account-rest-api/src/main/java/com/bobocode/config/WebConfig.java b/account-rest-api/src/main/java/com/bobocode/config/WebConfig.java index 6284d6a..2b1b98c 100644 --- a/account-rest-api/src/main/java/com/bobocode/config/WebConfig.java +++ b/account-rest-api/src/main/java/com/bobocode/config/WebConfig.java @@ -1,5 +1,10 @@ package com.bobocode.config; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Controller; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + /** * This class provides web (servlet) related configuration. *

@@ -7,6 +12,10 @@ * todo: 2. Enable web mvc using annotation * todo: 3. Enable component scanning for package "web" using annotation value */ +@EnableWebMvc +@Configuration +@ComponentScan("com.bobocode.web") public class WebConfig { } + diff --git a/account-rest-api/src/main/java/com/bobocode/dao/impl/InMemoryAccountDao.java b/account-rest-api/src/main/java/com/bobocode/dao/impl/InMemoryAccountDao.java index af5f026..0401391 100644 --- a/account-rest-api/src/main/java/com/bobocode/dao/impl/InMemoryAccountDao.java +++ b/account-rest-api/src/main/java/com/bobocode/dao/impl/InMemoryAccountDao.java @@ -3,6 +3,7 @@ import com.bobocode.dao.AccountDao; import com.bobocode.exception.EntityNotFountException; import com.bobocode.model.Account; +import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.HashMap; @@ -14,6 +15,7 @@ *

* 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/account-rest-api/src/main/java/com/bobocode/web/controller/AccountRestController.java b/account-rest-api/src/main/java/com/bobocode/web/controller/AccountRestController.java index 84fb818..88e609a 100644 --- a/account-rest-api/src/main/java/com/bobocode/web/controller/AccountRestController.java +++ b/account-rest-api/src/main/java/com/bobocode/web/controller/AccountRestController.java @@ -1,6 +1,12 @@ package com.bobocode.web.controller; import com.bobocode.dao.AccountDao; +import com.bobocode.model.Account; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Objects; /** *

@@ -16,6 +22,46 @@ * 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 */ +@RestController +@RequestMapping("/accounts") public class AccountRestController { + private final AccountDao accountDao; + + public AccountRestController(AccountDao accountDao) { + this.accountDao = accountDao; + } + + @GetMapping + public List getAll() { + return accountDao.findAll(); + } + + @GetMapping("/{id}") + public Account getOne(@PathVariable long id) { + return accountDao.findById(id); + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public Account create(@RequestBody Account account) { + return accountDao.save(account); + } + + @PutMapping("/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void update(@PathVariable long id, @RequestBody Account account) { + if (!Objects.equals(id, account.getId())) { + throw new IllegalStateException("Id parameter does not match account body value"); + } + accountDao.save(account); + } + + @DeleteMapping("/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void remove(@PathVariable long id) { + Account account = accountDao.findById(id); + accountDao.remove(account); + } } + diff --git a/hello-application-context/src/main/java/com/bobocode/config/AppConfig.java b/hello-application-context/src/main/java/com/bobocode/config/AppConfig.java index da2b1d9..e8b7038 100644 --- a/hello-application-context/src/main/java/com/bobocode/config/AppConfig.java +++ b/hello-application-context/src/main/java/com/bobocode/config/AppConfig.java @@ -1,6 +1,9 @@ package com.bobocode.config; import com.bobocode.TestDataGenerator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; /** * This class application context configuration. @@ -10,6 +13,12 @@ * todo: provide explicit configuration for a bean of type {@link TestDataGenerator} with name "dataGenerator" in this class. * todo: Don't specify bean name "dataGenerator" explicitly */ +@Configuration +@ComponentScan(basePackages = {"com.bobocode.dao","com.bobocode.service"}) public class AppConfig { + @Bean + public TestDataGenerator dataGenerator() { + return new TestDataGenerator(); + } } diff --git a/hello-application-context/src/main/java/com/bobocode/dao/FakeAccountDao.java b/hello-application-context/src/main/java/com/bobocode/dao/FakeAccountDao.java index a2e6b3e..bbdb6b4 100644 --- a/hello-application-context/src/main/java/com/bobocode/dao/FakeAccountDao.java +++ b/hello-application-context/src/main/java/com/bobocode/dao/FakeAccountDao.java @@ -3,6 +3,7 @@ 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; @@ -15,9 +16,11 @@ * todo: configure this class as Spring component with bean name "accountDao" * todo: use explicit (with {@link Autowired} annotation) constructor-based dependency injection */ +@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/hello-application-context/src/main/java/com/bobocode/service/AccountService.java b/hello-application-context/src/main/java/com/bobocode/service/AccountService.java index 1b036dd..5bbea2f 100644 --- a/hello-application-context/src/main/java/com/bobocode/service/AccountService.java +++ b/hello-application-context/src/main/java/com/bobocode/service/AccountService.java @@ -2,6 +2,7 @@ import com.bobocode.dao.AccountDao; import com.bobocode.model.Account; +import org.springframework.stereotype.Service; import java.util.Comparator; import java.util.List; @@ -12,6 +13,7 @@ * todo: configure {@link AccountService} bean implicitly using special annotation for service classes * todo: use implicit constructor-based dependency injection (don't use {@link org.springframework.beans.factory.annotation.Autowired}) */ +@Service public class AccountService { private final AccountDao accountDao; diff --git a/hello-spring-mvc/src/main/java/com/bobocode/config/RootConfig.java b/hello-spring-mvc/src/main/java/com/bobocode/config/RootConfig.java index bd4dad0..5782500 100644 --- a/hello-spring-mvc/src/main/java/com/bobocode/config/RootConfig.java +++ b/hello-spring-mvc/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.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Controller; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @@ -10,5 +13,7 @@ * 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(EnableWebMvc.class), @Filter(Controller.class)}) public class RootConfig { } diff --git a/hello-spring-mvc/src/main/java/com/bobocode/config/WebAppInitializer.java b/hello-spring-mvc/src/main/java/com/bobocode/config/WebAppInitializer.java index 0cec4ca..265a09d 100644 --- a/hello-spring-mvc/src/main/java/com/bobocode/config/WebAppInitializer.java +++ b/hello-spring-mvc/src/main/java/com/bobocode/config/WebAppInitializer.java @@ -12,16 +12,17 @@ public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class[] getRootConfigClasses() { - throw new UnsupportedOperationException("Method is not implemented yet!"); + return new Class[]{RootConfig.class}; } @Override protected Class[] getServletConfigClasses() { - throw new UnsupportedOperationException("Method is not implemented yet!"); + return new Class[]{WebConfig.class}; + } @Override protected String[] getServletMappings() { - throw new UnsupportedOperationException("Method is not implemented yet!"); + return new String[]{"/"}; } } diff --git a/hello-spring-mvc/src/main/java/com/bobocode/config/WebConfig.java b/hello-spring-mvc/src/main/java/com/bobocode/config/WebConfig.java index 975ea15..d94eb7f 100644 --- a/hello-spring-mvc/src/main/java/com/bobocode/config/WebConfig.java +++ b/hello-spring-mvc/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: enable web mvc using annotation * todo: enable component scanning for package "web" */ +@Configuration +@EnableWebMvc +@ComponentScan(basePackages = "com.bobocode.web") public class WebConfig { } diff --git a/hello-spring-mvc/src/main/java/com/bobocode/web/controller/WelcomeController.java b/hello-spring-mvc/src/main/java/com/bobocode/web/controller/WelcomeController.java index ca389bc..c1209c1 100644 --- a/hello-spring-mvc/src/main/java/com/bobocode/web/controller/WelcomeController.java +++ b/hello-spring-mvc/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. *

@@ -7,8 +11,11 @@ * todo: configure HTTP GET mapping "/welcome" for method {@link WelcomeController#welcome()} * todo: tell Spring that {@link WelcomeController#welcome()} method provides response body */ +@Controller public class WelcomeController { + @ResponseBody + @GetMapping("/welcome") public String welcome() { return "Welcome to Spring MVC!"; } diff --git a/inter-bean-dependencies/src/main/java/com/bobocode/config/RootConfig.java b/inter-bean-dependencies/src/main/java/com/bobocode/config/RootConfig.java index 40419b3..6d6bfca 100644 --- a/inter-bean-dependencies/src/main/java/com/bobocode/config/RootConfig.java +++ b/inter-bean-dependencies/src/main/java/com/bobocode/config/RootConfig.java @@ -5,26 +5,32 @@ import com.bobocode.dao.impl.FakeAccountDao; import com.bobocode.service.AccountService; import org.springframework.context.annotation.Bean; -import org.springframework.stereotype.Component; +import org.springframework.context.annotation.Configuration; /** * todo: Refactor {@link RootConfig} in order to user inter-bean dependencies properly. */ -@Component -public final class RootConfig { +@Configuration // @Configuration works a bit differently then @Component +// In this case Spring uses CGLIB to create a proxy in order to support inter-bean dependencies. +// It's when you call other method in your config class and still get the same bean instance +public class RootConfig { // Because CGLIB proxy is created as a subclass of your @Configuration class, RootConfig cannot be final @Bean public AccountService accountService() { - return new AccountService(fakeAccountDao()); + return new AccountService(fakeAccountDao()); // Although you call fakeAccountDao() method here, it is not called directly + // Spring creates proxy that overrides all these method. It caches created beans so when you call method like + // fakeAccountDao() it first checks if such beans was created before. + // It allows to support default bean scope SINGLETON. } @Bean - public final AccountDao fakeAccountDao() { + public AccountDao fakeAccountDao() { return new FakeAccountDao(dataGenerator()); } @Bean - private TestDataGenerator dataGenerator() { + public TestDataGenerator dataGenerator() { // Because Spring overrides methods in a proxy, + // bean methods in @Configuration classes cannot be final return new TestDataGenerator(); } } diff --git a/transactional-user-service/src/main/java/com/bobocode/config/JpaConfig.java b/transactional-user-service/src/main/java/com/bobocode/config/JpaConfig.java index 81c079d..dd6f746 100644 --- a/transactional-user-service/src/main/java/com/bobocode/config/JpaConfig.java +++ b/transactional-user-service/src/main/java/com/bobocode/config/JpaConfig.java @@ -1,5 +1,7 @@ package com.bobocode.config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.orm.jpa.JpaVendorAdapter; @@ -20,13 +22,16 @@ * todo: 4. Configure bean {@link javax.persistence.EntityManagerFactory} with name "entityManagerFactory" * */ +@Configuration public class JpaConfig { + @Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .build(); } + @Bean public JpaVendorAdapter jpaVendorAdapter() { HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter(); adapter.setDatabase(Database.H2); @@ -35,11 +40,12 @@ public JpaVendorAdapter jpaVendorAdapter() { return adapter; } + @Bean("entityManagerFactory") public LocalContainerEntityManagerFactoryBean localContainerEMF(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) { LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean(); emf.setDataSource(dataSource); emf.setJpaVendorAdapter(jpaVendorAdapter); - // todo: 5. Configure package "com.bobocode.model" to scan for JPA entities + emf.setPackagesToScan("com.bobocode.model"); return emf; } } diff --git a/transactional-user-service/src/main/java/com/bobocode/config/RootConfig.java b/transactional-user-service/src/main/java/com/bobocode/config/RootConfig.java index 58d3031..3828e95 100644 --- a/transactional-user-service/src/main/java/com/bobocode/config/RootConfig.java +++ b/transactional-user-service/src/main/java/com/bobocode/config/RootConfig.java @@ -1,6 +1,13 @@ package com.bobocode.config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.persistence.EntityManagerFactory; /** * This class provides root application configuration. It scans for all available beans and enables declarative @@ -11,6 +18,14 @@ * todo: 3. Configure JPA {@link PlatformTransactionManager} with bean name "transactionManager" * todo: 4. Enable declarative transaction management */ +@Configuration +@ComponentScan("com.bobocode") +@EnableTransactionManagement public class RootConfig { + @Bean + public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { + return new JpaTransactionManager(entityManagerFactory); + } } + diff --git a/transactional-user-service/src/main/java/com/bobocode/dao/impl/JpaUserDao.java b/transactional-user-service/src/main/java/com/bobocode/dao/impl/JpaUserDao.java index 050b2c7..a66d688 100644 --- a/transactional-user-service/src/main/java/com/bobocode/dao/impl/JpaUserDao.java +++ b/transactional-user-service/src/main/java/com/bobocode/dao/impl/JpaUserDao.java @@ -16,7 +16,10 @@ * todo: 2. Enable transaction management on class level * todo: 3. Inject {@link EntityManager} using @{@link PersistenceContext} annotation */ +@Transactional +@Repository("userDao") public class JpaUserDao implements UserDao { + @PersistenceContext private EntityManager entityManager; @Override @@ -34,3 +37,4 @@ public void save(User user) { entityManager.persist(user); } } + diff --git a/transactional-user-service/src/main/java/com/bobocode/service/UserService.java b/transactional-user-service/src/main/java/com/bobocode/service/UserService.java index ddbd598..1e5ed49 100644 --- a/transactional-user-service/src/main/java/com/bobocode/service/UserService.java +++ b/transactional-user-service/src/main/java/com/bobocode/service/UserService.java @@ -4,7 +4,10 @@ import com.bobocode.model.jpa.Role; import com.bobocode.model.jpa.RoleType; import com.bobocode.model.jpa.User; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.math.BigDecimal; import java.util.List; import static java.util.stream.Collectors.toList; @@ -18,19 +21,31 @@ * todo: 4. Configure {@link UserService#getAll()} as read-only method * todo: 4. Configure {@link UserService#getAllAdmins()} as read-only method */ +@Service +@Transactional public class UserService { private UserDao userDao; + public UserService(UserDao userDao) { + this.userDao = userDao; + } + public void save(User user) { userDao.save(user); } + @Transactional(readOnly = true) public List getAll() { return userDao.findAll(); } + @Transactional(readOnly = true) public List getAllAdmins() { - throw new UnsupportedOperationException("Don't be lazy and implement the method"); + return userDao.findAll().stream() + .filter(user -> user.getRoles().stream() + .map(Role::getRoleType) + .anyMatch(roleType -> roleType.equals(RoleType.ADMIN))) + .collect(toList()); } public void addRole(Long userId, RoleType roleType) { @@ -39,3 +54,4 @@ public void addRole(Long userId, RoleType roleType) { user.addRole(role); } } +