From c1b13d09314f92424cddca0c00171fc4ad87e139 Mon Sep 17 00:00:00 2001 From: Kirill Vlasov Date: Fri, 10 Apr 2020 20:21:01 +0500 Subject: [PATCH 01/17] BAEL-3969 Spring Security - Custom Logout Handler --- .../LogoutDemoApplication.java | 13 +++ .../customlogouthandler/MvcConfiguration.java | 51 +++++++++ .../services/UserCache.java | 33 ++++++ .../customlogouthandler/user/User.java | 61 ++++++++++ .../customlogouthandler/user/UserUtils.java | 13 +++ .../web/CustomLogoutHandler.java | 27 +++++ .../web/UserController.java | 30 +++++ ...application-customlogouthandler.properties | 5 + .../CustomLogoutHandlerIntegrationTest.java | 106 ++++++++++++++++++ .../resources/customlogouthandler/after.sql | 1 + .../application.properties | 5 + .../resources/customlogouthandler/before.sql | 1 + 12 files changed, 346 insertions(+) create mode 100644 spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/LogoutDemoApplication.java create mode 100644 spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/MvcConfiguration.java create mode 100644 spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/services/UserCache.java create mode 100644 spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/User.java create mode 100644 spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/UserUtils.java create mode 100644 spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/CustomLogoutHandler.java create mode 100644 spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/UserController.java create mode 100644 spring-security-modules/spring-security-mvc-boot-2/src/main/resources/application-customlogouthandler.properties create mode 100644 spring-security-modules/spring-security-mvc-boot-2/src/test/java/com/baeldung/customlogouthandler/CustomLogoutHandlerIntegrationTest.java create mode 100644 spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/after.sql create mode 100644 spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/application.properties create mode 100644 spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/before.sql diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/LogoutDemoApplication.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/LogoutDemoApplication.java new file mode 100644 index 0000000000..027334dd6b --- /dev/null +++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/LogoutDemoApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.customlogouthandler; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class LogoutDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(LogoutDemoApplication.class, args); + } + +} diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/MvcConfiguration.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/MvcConfiguration.java new file mode 100644 index 0000000000..36de049a31 --- /dev/null +++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/MvcConfiguration.java @@ -0,0 +1,51 @@ +package com.baeldung.customlogouthandler; + +import com.baeldung.customlogouthandler.web.CustomLogoutHandler; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler; + +import javax.sql.DataSource; + +@Configuration +@EnableWebSecurity +public class MvcConfiguration extends WebSecurityConfigurerAdapter { + + @Autowired + private DataSource dataSource; + + @Autowired + private CustomLogoutHandler logoutHandler; + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .httpBasic().and() + .authorizeRequests() + .antMatchers(HttpMethod.GET, "/user/**").hasRole("USER") + .and() + .logout() + .logoutUrl("/user/logout") + .addLogoutHandler(logoutHandler) + .logoutSuccessHandler((new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK))) + .permitAll() + .and() + .csrf().disable() + .formLogin().disable(); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.jdbcAuthentication() + .dataSource(dataSource) + .usersByUsernameQuery("select login, password, true from users where login=?") + .authoritiesByUsernameQuery("select login, role from users where login=?"); + } + +} diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/services/UserCache.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/services/UserCache.java new file mode 100644 index 0000000000..56c4d1e7c9 --- /dev/null +++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/services/UserCache.java @@ -0,0 +1,33 @@ +package com.baeldung.customlogouthandler.services; + +import com.baeldung.customlogouthandler.user.User; +import org.springframework.stereotype.Service; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +@Service +public class UserCache { + + @PersistenceContext + private EntityManager entityManager; + + private final ConcurrentMap store = new ConcurrentHashMap<>(256); + + public User getByLogin(String login) { + return store.computeIfAbsent(login, k -> entityManager.createQuery("from User where login=:login", User.class) + .setParameter("login", k) + .getSingleResult()); + } + + public void evictUser(String login) { + store.remove(login); + } + + public int size() { + return this.store.size(); + } + +} diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/User.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/User.java new file mode 100644 index 0000000000..ca3a998c5c --- /dev/null +++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/User.java @@ -0,0 +1,61 @@ +package com.baeldung.customlogouthandler.user; + +import javax.persistence.*; + +@Entity +@Table(name = "users") +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + @Column(unique = true) + private String login; + + private String password; + + private String role; + + private String language; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } +} diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/UserUtils.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/UserUtils.java new file mode 100644 index 0000000000..195497f7ba --- /dev/null +++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/UserUtils.java @@ -0,0 +1,13 @@ +package com.baeldung.customlogouthandler.user; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; + +public class UserUtils { + + public static String getAuthenticatedUserLogin() { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + return auth != null ? ((org.springframework.security.core.userdetails.User) auth.getPrincipal()).getUsername() : null; + } + +} diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/CustomLogoutHandler.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/CustomLogoutHandler.java new file mode 100644 index 0000000000..2a335cd122 --- /dev/null +++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/CustomLogoutHandler.java @@ -0,0 +1,27 @@ +package com.baeldung.customlogouthandler.web; + +import com.baeldung.customlogouthandler.services.UserCache; +import com.baeldung.customlogouthandler.user.UserUtils; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.logout.LogoutHandler; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@Service +public class CustomLogoutHandler implements LogoutHandler { + + private final UserCache userCache; + + public CustomLogoutHandler(UserCache userCache) { + this.userCache = userCache; + } + + @Override + public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { + String login = UserUtils.getAuthenticatedUserLogin(); + userCache.evictUser(login); + } + +} diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/UserController.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/UserController.java new file mode 100644 index 0000000000..18cd8dda98 --- /dev/null +++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/UserController.java @@ -0,0 +1,30 @@ +package com.baeldung.customlogouthandler.web; + +import com.baeldung.customlogouthandler.services.UserCache; +import com.baeldung.customlogouthandler.user.User; +import com.baeldung.customlogouthandler.user.UserUtils; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + + +@Controller +@RequestMapping(path = "/user") +public class UserController { + + private final UserCache userCache; + + public UserController(UserCache userCache) { + this.userCache = userCache; + } + + @GetMapping(path = "/language") + @ResponseBody + public String getLanguage() { + String login = UserUtils.getAuthenticatedUserLogin(); + User user = userCache.getByLogin(login); + return user.getLanguage(); + } + +} diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/resources/application-customlogouthandler.properties b/spring-security-modules/spring-security-mvc-boot-2/src/main/resources/application-customlogouthandler.properties new file mode 100644 index 0000000000..2cb766378d --- /dev/null +++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/resources/application-customlogouthandler.properties @@ -0,0 +1,5 @@ +spring.datasource.url=jdbc:postgresql://localhost:5432/test +spring.datasource.username=test +spring.datasource.password=test + +spring.jpa.hibernate.ddl-auto=create \ No newline at end of file diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/test/java/com/baeldung/customlogouthandler/CustomLogoutHandlerIntegrationTest.java b/spring-security-modules/spring-security-mvc-boot-2/src/test/java/com/baeldung/customlogouthandler/CustomLogoutHandlerIntegrationTest.java new file mode 100644 index 0000000000..3c325a2006 --- /dev/null +++ b/spring-security-modules/spring-security-mvc-boot-2/src/test/java/com/baeldung/customlogouthandler/CustomLogoutHandlerIntegrationTest.java @@ -0,0 +1,106 @@ +package com.baeldung.customlogouthandler; + +import com.baeldung.customlogouthandler.services.UserCache; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.jdbc.SqlGroup; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = {LogoutDemoApplication.class, MvcConfiguration.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@SqlGroup({ + @Sql(value = "classpath:customlogouthandler/before.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD), + @Sql(value = "classpath:customlogouthandler/after.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) +}) +class CustomLogoutHandlerIntegrationTest { + + @Autowired + private TestRestTemplate restTemplate; + + @Autowired + private UserCache userCache; + + @LocalServerPort + private int port; + + @Test + public void whenLogin_thenUseUserCache() throws Exception { + // User cache should be empty on start + assertThat(userCache.size()).isEqualTo(0); + + // Request using first login + ResponseEntity response = restTemplate + .withBasicAuth("user", "pass") + .getForEntity(getLanguageUrl(), String.class); + + assertThat(response.getBody()).contains("english"); + + // User cache must contain the user + assertThat(userCache.size()).isEqualTo(1); + + // Getting the session cookie + HttpHeaders requestHeaders = new HttpHeaders(); + requestHeaders.add("Cookie", response.getHeaders().getFirst(HttpHeaders.SET_COOKIE)); + + // Request with the session cookie + response = restTemplate + .exchange(getLanguageUrl(), HttpMethod.GET, new HttpEntity(requestHeaders), String.class); + assertThat(response.getBody()).contains("english"); + + // Logging out using the session cookies + response = restTemplate.exchange(getLogoutUrl(), HttpMethod.GET, new HttpEntity(requestHeaders), String.class); + assertThat(response.getStatusCode().value()).isEqualTo(200); + } + + @Test + public void whenLogout_thenCacheIsEmpty() throws Exception { + // User cache should be empty on start + assertThat(userCache.size()).isEqualTo(0); + + // Request using first login + ResponseEntity response = restTemplate + .withBasicAuth("user", "pass") + .getForEntity(getLanguageUrl(), String.class); + + assertThat(response.getBody()).contains("english"); + + // User cache must contain the user + assertThat(userCache.size()).isEqualTo(1); + + // Getting the session cookie + HttpHeaders requestHeaders = new HttpHeaders(); + requestHeaders.add("Cookie", response.getHeaders().getFirst(HttpHeaders.SET_COOKIE)); + + // Logging out using the session cookies + response = restTemplate.exchange(getLogoutUrl(), HttpMethod.GET, new HttpEntity(requestHeaders), String.class); + assertThat(response.getStatusCode().value()).isEqualTo(200); + + // User cache must be empty now + // this is the reaction on custom logout filter execution + assertThat(userCache.size()).isEqualTo(0); + + // Assert unathorized request + response = restTemplate.exchange(getLanguageUrl(), HttpMethod.GET, new HttpEntity(requestHeaders), String.class); + assertThat(response.getStatusCode().value()).isEqualTo(401); + } + + private String getLanguageUrl() { + return "http://localhost:" + port + "/user/language"; + } + + private String getLogoutUrl() { + return "http://localhost:" + port + "/user/logout"; + } + +} diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/after.sql b/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/after.sql new file mode 100644 index 0000000000..df6f312987 --- /dev/null +++ b/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/after.sql @@ -0,0 +1 @@ +delete from users; \ No newline at end of file diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/application.properties b/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/application.properties new file mode 100644 index 0000000000..8b6d47ebe9 --- /dev/null +++ b/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/application.properties @@ -0,0 +1,5 @@ +spring.datasource.url=jdbc:postgresql://localhost:5432/develop +spring.datasource.username=develop +spring.datasource.password=develop + +spring.jpa.hibernate.ddl-auto=create diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/before.sql b/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/before.sql new file mode 100644 index 0000000000..bb0a85f613 --- /dev/null +++ b/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/before.sql @@ -0,0 +1 @@ +insert into users (login, password, role, language) values ('user', '{noop}pass', 'ROLE_USER', 'english'); \ No newline at end of file From 07b5c1f01020dfbd7a3dfa17054f21347d451c65 Mon Sep 17 00:00:00 2001 From: Kirill Vlasov Date: Sun, 12 Apr 2020 16:16:36 +0500 Subject: [PATCH 02/17] Code review fixes --- ...tion.java => CustomLogoutApplication.java} | 8 +- .../customlogouthandler/MvcConfiguration.java | 30 ++-- .../services/UserCache.java | 24 ++-- .../customlogouthandler/user/UserUtils.java | 5 +- .../web/CustomLogoutHandler.java | 13 +- .../web/UserController.java | 10 +- .../CustomLogoutHandlerIntegrationTest.java | 132 +++++++++--------- .../application.properties | 6 +- 8 files changed, 119 insertions(+), 109 deletions(-) rename spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/{LogoutDemoApplication.java => CustomLogoutApplication.java} (54%) diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/LogoutDemoApplication.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/CustomLogoutApplication.java similarity index 54% rename from spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/LogoutDemoApplication.java rename to spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/CustomLogoutApplication.java index 027334dd6b..39d867b1f4 100644 --- a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/LogoutDemoApplication.java +++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/CustomLogoutApplication.java @@ -4,10 +4,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -public class LogoutDemoApplication { +public class CustomLogoutApplication { - public static void main(String[] args) { - SpringApplication.run(LogoutDemoApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(CustomLogoutApplication.class, args); + } } diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/MvcConfiguration.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/MvcConfiguration.java index 36de049a31..3e17a7c397 100644 --- a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/MvcConfiguration.java +++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/MvcConfiguration.java @@ -1,6 +1,7 @@ package com.baeldung.customlogouthandler; -import com.baeldung.customlogouthandler.web.CustomLogoutHandler; +import javax.sql.DataSource; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; @@ -11,7 +12,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler; -import javax.sql.DataSource; +import com.baeldung.customlogouthandler.web.CustomLogoutHandler; @Configuration @EnableWebSecurity @@ -25,27 +26,30 @@ public class MvcConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { - http - .httpBasic().and() + http.httpBasic() + .and() .authorizeRequests() - .antMatchers(HttpMethod.GET, "/user/**").hasRole("USER") - .and() - .logout() + .antMatchers(HttpMethod.GET, "/user/**") + .hasRole("USER") + .and() + .logout() .logoutUrl("/user/logout") .addLogoutHandler(logoutHandler) .logoutSuccessHandler((new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK))) .permitAll() - .and() - .csrf().disable() - .formLogin().disable(); + .and() + .csrf() + .disable() + .formLogin() + .disable(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.jdbcAuthentication() - .dataSource(dataSource) - .usersByUsernameQuery("select login, password, true from users where login=?") - .authoritiesByUsernameQuery("select login, role from users where login=?"); + .dataSource(dataSource) + .usersByUsernameQuery("select login, password, true from users where login=?") + .authoritiesByUsernameQuery("select login, role from users where login=?"); } } diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/services/UserCache.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/services/UserCache.java index 56c4d1e7c9..b86edc0dee 100644 --- a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/services/UserCache.java +++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/services/UserCache.java @@ -1,12 +1,14 @@ package com.baeldung.customlogouthandler.services; -import com.baeldung.customlogouthandler.user.User; -import org.springframework.stereotype.Service; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; + +import org.springframework.stereotype.Service; + +import com.baeldung.customlogouthandler.user.User; @Service public class UserCache { @@ -16,18 +18,18 @@ public class UserCache { private final ConcurrentMap store = new ConcurrentHashMap<>(256); - public User getByLogin(String login) { - return store.computeIfAbsent(login, k -> entityManager.createQuery("from User where login=:login", User.class) - .setParameter("login", k) - .getSingleResult()); + public User getByUserName(String userName) { + return store.computeIfAbsent(userName, k -> entityManager.createQuery("from User where login=:login", User.class) + .setParameter("login", k) + .getSingleResult()); } - public void evictUser(String login) { - store.remove(login); + public void evictUser(String userName) { + store.remove(userName); } public int size() { - return this.store.size(); + return store.size(); } } diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/UserUtils.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/UserUtils.java index 195497f7ba..aa9a521b01 100644 --- a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/UserUtils.java +++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/UserUtils.java @@ -5,8 +5,9 @@ import org.springframework.security.core.context.SecurityContextHolder; public class UserUtils { - public static String getAuthenticatedUserLogin() { - Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + public static String getAuthenticatedUserName() { + Authentication auth = SecurityContextHolder.getContext() + .getAuthentication(); return auth != null ? ((org.springframework.security.core.userdetails.User) auth.getPrincipal()).getUsername() : null; } diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/CustomLogoutHandler.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/CustomLogoutHandler.java index 2a335cd122..a89c9a570d 100644 --- a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/CustomLogoutHandler.java +++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/CustomLogoutHandler.java @@ -1,13 +1,14 @@ package com.baeldung.customlogouthandler.web; -import com.baeldung.customlogouthandler.services.UserCache; -import com.baeldung.customlogouthandler.user.UserUtils; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.stereotype.Service; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import com.baeldung.customlogouthandler.services.UserCache; +import com.baeldung.customlogouthandler.user.UserUtils; @Service public class CustomLogoutHandler implements LogoutHandler { @@ -20,8 +21,8 @@ public class CustomLogoutHandler implements LogoutHandler { @Override public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { - String login = UserUtils.getAuthenticatedUserLogin(); - userCache.evictUser(login); + String userName = UserUtils.getAuthenticatedUserName(); + userCache.evictUser(userName); } } diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/UserController.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/UserController.java index 18cd8dda98..b2d332a1bb 100644 --- a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/UserController.java +++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/UserController.java @@ -1,13 +1,13 @@ package com.baeldung.customlogouthandler.web; -import com.baeldung.customlogouthandler.services.UserCache; -import com.baeldung.customlogouthandler.user.User; -import com.baeldung.customlogouthandler.user.UserUtils; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; +import com.baeldung.customlogouthandler.services.UserCache; +import com.baeldung.customlogouthandler.user.User; +import com.baeldung.customlogouthandler.user.UserUtils; @Controller @RequestMapping(path = "/user") @@ -22,8 +22,8 @@ public class UserController { @GetMapping(path = "/language") @ResponseBody public String getLanguage() { - String login = UserUtils.getAuthenticatedUserLogin(); - User user = userCache.getByLogin(login); + String userName = UserUtils.getAuthenticatedUserName(); + User user = userCache.getByUserName(userName); return user.getLanguage(); } diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/test/java/com/baeldung/customlogouthandler/CustomLogoutHandlerIntegrationTest.java b/spring-security-modules/spring-security-mvc-boot-2/src/test/java/com/baeldung/customlogouthandler/CustomLogoutHandlerIntegrationTest.java index 3c325a2006..cd8a1a72d6 100644 --- a/spring-security-modules/spring-security-mvc-boot-2/src/test/java/com/baeldung/customlogouthandler/CustomLogoutHandlerIntegrationTest.java +++ b/spring-security-modules/spring-security-mvc-boot-2/src/test/java/com/baeldung/customlogouthandler/CustomLogoutHandlerIntegrationTest.java @@ -1,6 +1,7 @@ package com.baeldung.customlogouthandler; -import com.baeldung.customlogouthandler.services.UserCache; +import static org.assertj.core.api.Assertions.assertThat; + import org.junit.jupiter.api.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -11,96 +12,97 @@ import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; +import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.SqlGroup; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import static org.assertj.core.api.Assertions.assertThat; +import com.baeldung.customlogouthandler.services.UserCache; @RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest(classes = {LogoutDemoApplication.class, MvcConfiguration.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@SqlGroup({ - @Sql(value = "classpath:customlogouthandler/before.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD), - @Sql(value = "classpath:customlogouthandler/after.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) -}) +@SpringBootTest(classes = { CustomLogoutApplication.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@SqlGroup({ @Sql(value = "classpath:customlogouthandler/before.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD), @Sql(value = "classpath:customlogouthandler/after.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) }) +@TestPropertySource(locations="classpath:customlogouthandler/application.properties") class CustomLogoutHandlerIntegrationTest { - @Autowired - private TestRestTemplate restTemplate; + @Autowired + private TestRestTemplate restTemplate; - @Autowired - private UserCache userCache; + @Autowired + private UserCache userCache; - @LocalServerPort - private int port; + @LocalServerPort + private int port; - @Test - public void whenLogin_thenUseUserCache() throws Exception { - // User cache should be empty on start - assertThat(userCache.size()).isEqualTo(0); + @Test + public void whenLogin_thenUseUserCache() { + // User cache should be empty on start + assertThat(userCache.size()).isEqualTo(0); - // Request using first login - ResponseEntity response = restTemplate - .withBasicAuth("user", "pass") - .getForEntity(getLanguageUrl(), String.class); + // Request using first login + ResponseEntity response = restTemplate.withBasicAuth("user", "pass") + .getForEntity(getLanguageUrl(), String.class); - assertThat(response.getBody()).contains("english"); + assertThat(response.getBody()).contains("english"); - // User cache must contain the user - assertThat(userCache.size()).isEqualTo(1); + // User cache must contain the user + assertThat(userCache.size()).isEqualTo(1); - // Getting the session cookie - HttpHeaders requestHeaders = new HttpHeaders(); - requestHeaders.add("Cookie", response.getHeaders().getFirst(HttpHeaders.SET_COOKIE)); + // Getting the session cookie + HttpHeaders requestHeaders = new HttpHeaders(); + requestHeaders.add("Cookie", response.getHeaders() + .getFirst(HttpHeaders.SET_COOKIE)); - // Request with the session cookie - response = restTemplate - .exchange(getLanguageUrl(), HttpMethod.GET, new HttpEntity(requestHeaders), String.class); - assertThat(response.getBody()).contains("english"); + // Request with the session cookie + response = restTemplate.exchange(getLanguageUrl(), HttpMethod.GET, new HttpEntity(requestHeaders), String.class); + assertThat(response.getBody()).contains("english"); - // Logging out using the session cookies - response = restTemplate.exchange(getLogoutUrl(), HttpMethod.GET, new HttpEntity(requestHeaders), String.class); - assertThat(response.getStatusCode().value()).isEqualTo(200); - } + // Logging out using the session cookies + response = restTemplate.exchange(getLogoutUrl(), HttpMethod.GET, new HttpEntity(requestHeaders), String.class); + assertThat(response.getStatusCode() + .value()).isEqualTo(200); + } - @Test - public void whenLogout_thenCacheIsEmpty() throws Exception { - // User cache should be empty on start - assertThat(userCache.size()).isEqualTo(0); + @Test + public void whenLogout_thenCacheIsEmpty() { + // User cache should be empty on start + assertThat(userCache.size()).isEqualTo(0); - // Request using first login - ResponseEntity response = restTemplate - .withBasicAuth("user", "pass") - .getForEntity(getLanguageUrl(), String.class); + // Request using first login + ResponseEntity response = restTemplate.withBasicAuth("user", "pass") + .getForEntity(getLanguageUrl(), String.class); - assertThat(response.getBody()).contains("english"); + assertThat(response.getBody()).contains("english"); - // User cache must contain the user - assertThat(userCache.size()).isEqualTo(1); + // User cache must contain the user + assertThat(userCache.size()).isEqualTo(1); - // Getting the session cookie - HttpHeaders requestHeaders = new HttpHeaders(); - requestHeaders.add("Cookie", response.getHeaders().getFirst(HttpHeaders.SET_COOKIE)); + // Getting the session cookie + HttpHeaders requestHeaders = new HttpHeaders(); + requestHeaders.add("Cookie", response.getHeaders() + .getFirst(HttpHeaders.SET_COOKIE)); - // Logging out using the session cookies - response = restTemplate.exchange(getLogoutUrl(), HttpMethod.GET, new HttpEntity(requestHeaders), String.class); - assertThat(response.getStatusCode().value()).isEqualTo(200); + // Logging out using the session cookies + response = restTemplate.exchange(getLogoutUrl(), HttpMethod.GET, new HttpEntity(requestHeaders), String.class); + assertThat(response.getStatusCode() + .value()).isEqualTo(200); - // User cache must be empty now - // this is the reaction on custom logout filter execution - assertThat(userCache.size()).isEqualTo(0); + // User cache must be empty now + // this is the reaction on custom logout filter execution + assertThat(userCache.size()).isEqualTo(0); - // Assert unathorized request - response = restTemplate.exchange(getLanguageUrl(), HttpMethod.GET, new HttpEntity(requestHeaders), String.class); - assertThat(response.getStatusCode().value()).isEqualTo(401); - } + // Assert unauthorized request + response = restTemplate.exchange(getLanguageUrl(), HttpMethod.GET, new HttpEntity(requestHeaders), String.class); + assertThat(response.getStatusCode() + .value()).isEqualTo(401); + } - private String getLanguageUrl() { - return "http://localhost:" + port + "/user/language"; - } + private String getLanguageUrl() { + return "http://localhost:" + port + "/user/language"; + } - private String getLogoutUrl() { - return "http://localhost:" + port + "/user/logout"; - } + private String getLogoutUrl() { + return "http://localhost:" + port + "/user/logout"; + } } diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/application.properties b/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/application.properties index 8b6d47ebe9..9edd853f2c 100644 --- a/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/application.properties +++ b/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/application.properties @@ -1,5 +1,5 @@ -spring.datasource.url=jdbc:postgresql://localhost:5432/develop -spring.datasource.username=develop -spring.datasource.password=develop +spring.datasource.url=jdbc:postgresql://localhost:5432/test +spring.datasource.username=test +spring.datasource.password=test spring.jpa.hibernate.ddl-auto=create From 7678f4a0cc7feb670715f7f3c3124bbdebc9bec5 Mon Sep 17 00:00:00 2001 From: Kirill Vlasov Date: Sat, 18 Apr 2020 08:00:52 +0500 Subject: [PATCH 03/17] Code review --- .../java/com/baeldung/customlogouthandler/MvcConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/MvcConfiguration.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/MvcConfiguration.java index 3e17a7c397..c363effb4e 100644 --- a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/MvcConfiguration.java +++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/MvcConfiguration.java @@ -35,7 +35,7 @@ public class MvcConfiguration extends WebSecurityConfigurerAdapter { .logout() .logoutUrl("/user/logout") .addLogoutHandler(logoutHandler) - .logoutSuccessHandler((new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK))) + .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK)) .permitAll() .and() .csrf() From 374905467e7ed9769c9cd6d834652a7198a22350 Mon Sep 17 00:00:00 2001 From: Justin Albano Date: Sat, 18 Apr 2020 11:48:26 -0400 Subject: [PATCH 04/17] BAEL-3965: Created examples for instance and static factory methods. --- .../java/com/baeldung/factorymethod/Bar.java | 18 ++++++++++++++ .../java/com/baeldung/factorymethod/Foo.java | 5 ++++ .../factorymethod/InstanceBarFactory.java | 8 +++++++ .../factorymethod/InstanceFooFactory.java | 8 +++++++ .../factorymethod/SingletonBarFactory.java | 11 +++++++++ .../factorymethod/SingletonFooFactory.java | 10 ++++++++ .../InstanceBarFactoryIntegrationTest.java | 24 +++++++++++++++++++ .../InstanceFooFactoryIntegrationTest.java | 22 +++++++++++++++++ .../SingletonBarFactoryIntegrationTest.java | 24 +++++++++++++++++++ .../SingletonFooFactoryIntegrationTest.java | 22 +++++++++++++++++ .../factorymethod/instance-bar-config.xml | 20 ++++++++++++++++ .../factorymethod/instance-foo-config.xml | 18 ++++++++++++++ .../factorymethod/static-bar-config.xml | 20 ++++++++++++++++ .../factorymethod/static-foo-config.xml | 18 ++++++++++++++ 14 files changed, 228 insertions(+) create mode 100644 spring-core-3/src/main/java/com/baeldung/factorymethod/Bar.java create mode 100644 spring-core-3/src/main/java/com/baeldung/factorymethod/Foo.java create mode 100644 spring-core-3/src/main/java/com/baeldung/factorymethod/InstanceBarFactory.java create mode 100644 spring-core-3/src/main/java/com/baeldung/factorymethod/InstanceFooFactory.java create mode 100644 spring-core-3/src/main/java/com/baeldung/factorymethod/SingletonBarFactory.java create mode 100644 spring-core-3/src/main/java/com/baeldung/factorymethod/SingletonFooFactory.java create mode 100644 spring-core-3/src/test/java/com/baeldung/factorymethod/InstanceBarFactoryIntegrationTest.java create mode 100644 spring-core-3/src/test/java/com/baeldung/factorymethod/InstanceFooFactoryIntegrationTest.java create mode 100644 spring-core-3/src/test/java/com/baeldung/factorymethod/SingletonBarFactoryIntegrationTest.java create mode 100644 spring-core-3/src/test/java/com/baeldung/factorymethod/SingletonFooFactoryIntegrationTest.java create mode 100644 spring-core-3/src/test/resources/factorymethod/instance-bar-config.xml create mode 100644 spring-core-3/src/test/resources/factorymethod/instance-foo-config.xml create mode 100644 spring-core-3/src/test/resources/factorymethod/static-bar-config.xml create mode 100644 spring-core-3/src/test/resources/factorymethod/static-foo-config.xml diff --git a/spring-core-3/src/main/java/com/baeldung/factorymethod/Bar.java b/spring-core-3/src/main/java/com/baeldung/factorymethod/Bar.java new file mode 100644 index 0000000000..22ef5b3429 --- /dev/null +++ b/spring-core-3/src/main/java/com/baeldung/factorymethod/Bar.java @@ -0,0 +1,18 @@ +package com.baeldung.factorymethod; + +public class Bar { + + private String name; + + public Bar(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/spring-core-3/src/main/java/com/baeldung/factorymethod/Foo.java b/spring-core-3/src/main/java/com/baeldung/factorymethod/Foo.java new file mode 100644 index 0000000000..54bd0c9ff4 --- /dev/null +++ b/spring-core-3/src/main/java/com/baeldung/factorymethod/Foo.java @@ -0,0 +1,5 @@ +package com.baeldung.factorymethod; + +public class Foo { + +} diff --git a/spring-core-3/src/main/java/com/baeldung/factorymethod/InstanceBarFactory.java b/spring-core-3/src/main/java/com/baeldung/factorymethod/InstanceBarFactory.java new file mode 100644 index 0000000000..f834b82aee --- /dev/null +++ b/spring-core-3/src/main/java/com/baeldung/factorymethod/InstanceBarFactory.java @@ -0,0 +1,8 @@ +package com.baeldung.factorymethod; + +public class InstanceBarFactory { + + public Bar createInstance(String name) { + return new Bar(name); + } +} diff --git a/spring-core-3/src/main/java/com/baeldung/factorymethod/InstanceFooFactory.java b/spring-core-3/src/main/java/com/baeldung/factorymethod/InstanceFooFactory.java new file mode 100644 index 0000000000..c3125d3339 --- /dev/null +++ b/spring-core-3/src/main/java/com/baeldung/factorymethod/InstanceFooFactory.java @@ -0,0 +1,8 @@ +package com.baeldung.factorymethod; + +public class InstanceFooFactory { + + public Foo createInstance() { + return new Foo(); + } +} diff --git a/spring-core-3/src/main/java/com/baeldung/factorymethod/SingletonBarFactory.java b/spring-core-3/src/main/java/com/baeldung/factorymethod/SingletonBarFactory.java new file mode 100644 index 0000000000..93802819b1 --- /dev/null +++ b/spring-core-3/src/main/java/com/baeldung/factorymethod/SingletonBarFactory.java @@ -0,0 +1,11 @@ +package com.baeldung.factorymethod; + +public class SingletonBarFactory { + + private static final Bar INSTANCE = new Bar("unnamed"); + + public static Bar createInstance(String name) { + INSTANCE.setName(name); + return INSTANCE; + } +} diff --git a/spring-core-3/src/main/java/com/baeldung/factorymethod/SingletonFooFactory.java b/spring-core-3/src/main/java/com/baeldung/factorymethod/SingletonFooFactory.java new file mode 100644 index 0000000000..77d56cc7f6 --- /dev/null +++ b/spring-core-3/src/main/java/com/baeldung/factorymethod/SingletonFooFactory.java @@ -0,0 +1,10 @@ +package com.baeldung.factorymethod; + +public class SingletonFooFactory { + + private static final Foo INSTANCE = new Foo(); + + public static Foo createInstance() { + return INSTANCE; + } +} diff --git a/spring-core-3/src/test/java/com/baeldung/factorymethod/InstanceBarFactoryIntegrationTest.java b/spring-core-3/src/test/java/com/baeldung/factorymethod/InstanceBarFactoryIntegrationTest.java new file mode 100644 index 0000000000..b5728316e7 --- /dev/null +++ b/spring-core-3/src/test/java/com/baeldung/factorymethod/InstanceBarFactoryIntegrationTest.java @@ -0,0 +1,24 @@ +package com.baeldung.factorymethod; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("/factorymethod/instance-bar-config.xml") +public class InstanceBarFactoryIntegrationTest { + + @Autowired + private Bar instance; + + @Test + public void givenValidInstanceFactoryConfig_whenCreateInstance_thenNameIsCorrect() { + assertNotNull(instance); + assertEquals("someName", instance.getName()); + } +} diff --git a/spring-core-3/src/test/java/com/baeldung/factorymethod/InstanceFooFactoryIntegrationTest.java b/spring-core-3/src/test/java/com/baeldung/factorymethod/InstanceFooFactoryIntegrationTest.java new file mode 100644 index 0000000000..6b1857c2f2 --- /dev/null +++ b/spring-core-3/src/test/java/com/baeldung/factorymethod/InstanceFooFactoryIntegrationTest.java @@ -0,0 +1,22 @@ +package com.baeldung.factorymethod; + +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("/factorymethod/instance-foo-config.xml") +public class InstanceFooFactoryIntegrationTest { + + @Autowired + private Foo foo; + + @Test + public void givenValidInstanceFactoryConfig_whenCreateFooInstance_thenInstanceIsNotNull() { + assertNotNull(foo); + } +} diff --git a/spring-core-3/src/test/java/com/baeldung/factorymethod/SingletonBarFactoryIntegrationTest.java b/spring-core-3/src/test/java/com/baeldung/factorymethod/SingletonBarFactoryIntegrationTest.java new file mode 100644 index 0000000000..403b46156b --- /dev/null +++ b/spring-core-3/src/test/java/com/baeldung/factorymethod/SingletonBarFactoryIntegrationTest.java @@ -0,0 +1,24 @@ +package com.baeldung.factorymethod; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("/factorymethod/static-bar-config.xml") +public class SingletonBarFactoryIntegrationTest { + + @Autowired + private Bar instance; + + @Test + public void givenValidStaticFactoryConfig_whenCreateInstance_thenNameIsCorrect() { + assertNotNull(instance); + assertEquals("someName", instance.getName()); + } +} diff --git a/spring-core-3/src/test/java/com/baeldung/factorymethod/SingletonFooFactoryIntegrationTest.java b/spring-core-3/src/test/java/com/baeldung/factorymethod/SingletonFooFactoryIntegrationTest.java new file mode 100644 index 0000000000..52154b81ab --- /dev/null +++ b/spring-core-3/src/test/java/com/baeldung/factorymethod/SingletonFooFactoryIntegrationTest.java @@ -0,0 +1,22 @@ +package com.baeldung.factorymethod; + +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("/factorymethod/static-foo-config.xml") +public class SingletonFooFactoryIntegrationTest { + + @Autowired + private Foo singleton; + + @Test + public void givenValidStaticFactoryConfig_whenCreateInstance_thenInstanceIsNotNull() { + assertNotNull(singleton); + } +} diff --git a/spring-core-3/src/test/resources/factorymethod/instance-bar-config.xml b/spring-core-3/src/test/resources/factorymethod/instance-bar-config.xml new file mode 100644 index 0000000000..40d2f33683 --- /dev/null +++ b/spring-core-3/src/test/resources/factorymethod/instance-bar-config.xml @@ -0,0 +1,20 @@ + + + + + + + + + + \ No newline at end of file diff --git a/spring-core-3/src/test/resources/factorymethod/instance-foo-config.xml b/spring-core-3/src/test/resources/factorymethod/instance-foo-config.xml new file mode 100644 index 0000000000..c45bef6a85 --- /dev/null +++ b/spring-core-3/src/test/resources/factorymethod/instance-foo-config.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/spring-core-3/src/test/resources/factorymethod/static-bar-config.xml b/spring-core-3/src/test/resources/factorymethod/static-bar-config.xml new file mode 100644 index 0000000000..4d1befc645 --- /dev/null +++ b/spring-core-3/src/test/resources/factorymethod/static-bar-config.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/spring-core-3/src/test/resources/factorymethod/static-foo-config.xml b/spring-core-3/src/test/resources/factorymethod/static-foo-config.xml new file mode 100644 index 0000000000..83e61a656c --- /dev/null +++ b/spring-core-3/src/test/resources/factorymethod/static-foo-config.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file From 1639ead274ffbb256016ec36f6fa6f7a1c08cd58 Mon Sep 17 00:00:00 2001 From: Donato Rimenti Date: Mon, 20 Apr 2020 19:36:51 +0200 Subject: [PATCH 05/17] [BAEL-3489] Added Java-R integration examples. --- libraries-data-2/pom.xml | 43 +++++++++++++++++++ .../main/java/com/baeldung/r/FastRMean.java | 28 ++++++++++++ .../main/java/com/baeldung/r/RCallerMean.java | 36 ++++++++++++++++ .../src/main/java/com/baeldung/r/RUtils.java | 30 +++++++++++++ .../main/java/com/baeldung/r/RenjinMean.java | 36 ++++++++++++++++ .../main/java/com/baeldung/r/RserveMean.java | 29 +++++++++++++ .../com/baeldung/r/FastRMeanUnitTest.java | 29 +++++++++++++ .../r/RCallerMeanIntegrationTest.java | 37 ++++++++++++++++ .../com/baeldung/r/RenjinMeanUnitTest.java | 37 ++++++++++++++++ libraries-data-2/src/test/resources/script.R | 3 ++ 10 files changed, 308 insertions(+) create mode 100644 libraries-data-2/src/main/java/com/baeldung/r/FastRMean.java create mode 100644 libraries-data-2/src/main/java/com/baeldung/r/RCallerMean.java create mode 100644 libraries-data-2/src/main/java/com/baeldung/r/RUtils.java create mode 100644 libraries-data-2/src/main/java/com/baeldung/r/RenjinMean.java create mode 100644 libraries-data-2/src/main/java/com/baeldung/r/RserveMean.java create mode 100644 libraries-data-2/src/test/java/com/baeldung/r/FastRMeanUnitTest.java create mode 100644 libraries-data-2/src/test/java/com/baeldung/r/RCallerMeanIntegrationTest.java create mode 100644 libraries-data-2/src/test/java/com/baeldung/r/RenjinMeanUnitTest.java create mode 100644 libraries-data-2/src/test/resources/script.R diff --git a/libraries-data-2/pom.xml b/libraries-data-2/pom.xml index e6106c0fe3..ce15ef6c07 100644 --- a/libraries-data-2/pom.xml +++ b/libraries-data-2/pom.xml @@ -128,6 +128,24 @@ ${awaitility.version} test + + + org.rosuda.REngine + Rserve + ${rserve.version} + + + + com.github.jbytecode + RCaller + ${rcaller.version} + + + + org.renjin + renjin-script-engine + ${renjin.version} + @@ -137,6 +155,13 @@ http://repo.numericalmethod.com/maven/ default + + + + bedatadriven + bedatadriven public repo + https://nexus.bedatadriven.com/content/groups/public/ + @@ -153,6 +178,24 @@ 3.6.2 1.7.25 3.0.0 + RELEASE + 3.0 + 1.8.1 + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + com/baeldung/r/FastRMean.java + + + + + + \ No newline at end of file diff --git a/libraries-data-2/src/main/java/com/baeldung/r/FastRMean.java b/libraries-data-2/src/main/java/com/baeldung/r/FastRMean.java new file mode 100644 index 0000000000..52fb2d1506 --- /dev/null +++ b/libraries-data-2/src/main/java/com/baeldung/r/FastRMean.java @@ -0,0 +1,28 @@ +package com.baeldung.r; + +import java.io.IOException; +import java.net.URISyntaxException; + +/** + * FastR showcase. + * + * @author Donato Rimenti + */ +public class FastRMean { + + /** + * Invokes the customMean R function passing the given values as arguments. + * + * @param values the input to the mean script + * @return the result of the R script + */ + public double mean(int[] values) { + Context polyglot = Context.newBuilder().allowAllAccess(true).build(); + String meanScriptContent = RUtils.getMeanScriptContent(); + polyglot.eval("R", meanScriptContent); + Value rBindings = polyglot.getBindings("R"); + Value rInput = rBindings.getMember("c").execute(values); + return rBindings.getMember("customMean").execute(rInput).asDouble(); + } + +} \ No newline at end of file diff --git a/libraries-data-2/src/main/java/com/baeldung/r/RCallerMean.java b/libraries-data-2/src/main/java/com/baeldung/r/RCallerMean.java new file mode 100644 index 0000000000..53e0ab9e31 --- /dev/null +++ b/libraries-data-2/src/main/java/com/baeldung/r/RCallerMean.java @@ -0,0 +1,36 @@ +package com.baeldung.r; + +import java.io.IOException; +import java.net.URISyntaxException; + +import com.github.rcaller.rstuff.RCaller; +import com.github.rcaller.rstuff.RCallerOptions; +import com.github.rcaller.rstuff.RCode; + +/** + * RCaller showcase. + * + * @author Donato Rimenti + */ +public class RCallerMean { + + /** + * Invokes the customMean R function passing the given values as arguments. + * + * @param values the input to the mean script + * @return the result of the R script + * @throws IOException if any error occurs + * @throws URISyntaxException if any error occurs + */ + public double mean(int[] values) throws IOException, URISyntaxException { + String fileContent = RUtils.getMeanScriptContent(); + RCode code = RCode.create(); + code.addRCode(fileContent); + code.addIntArray("input", values); + code.addRCode("result <- customMean(input)"); + RCaller caller = RCaller.create(code, RCallerOptions.create()); + caller.runAndReturnResult("result"); + return caller.getParser().getAsDoubleArray("result")[0]; + } + +} \ No newline at end of file diff --git a/libraries-data-2/src/main/java/com/baeldung/r/RUtils.java b/libraries-data-2/src/main/java/com/baeldung/r/RUtils.java new file mode 100644 index 0000000000..ad16fd5602 --- /dev/null +++ b/libraries-data-2/src/main/java/com/baeldung/r/RUtils.java @@ -0,0 +1,30 @@ +package com.baeldung.r; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.stream.Collectors; + +/** + * Utility class for loading the script.R content. + * + * @author Donato Rimenti + */ +public class RUtils { + + /** + * Loads the script.R and returns its content as a string. + * + * @return the script.R content as a string + * @throws IOException if any error occurs + * @throws URISyntaxException if any error occurs + */ + static String getMeanScriptContent() throws IOException, URISyntaxException { + URI rScriptUri = RUtils.class.getClassLoader().getResource("script.R").toURI(); + Path inputScript = Paths.get(rScriptUri); + return Files.lines(inputScript).collect(Collectors.joining()); + } +} \ No newline at end of file diff --git a/libraries-data-2/src/main/java/com/baeldung/r/RenjinMean.java b/libraries-data-2/src/main/java/com/baeldung/r/RenjinMean.java new file mode 100644 index 0000000000..befb7d522f --- /dev/null +++ b/libraries-data-2/src/main/java/com/baeldung/r/RenjinMean.java @@ -0,0 +1,36 @@ +package com.baeldung.r; + +import java.io.IOException; +import java.net.URISyntaxException; + +import javax.script.ScriptException; + +import org.renjin.script.RenjinScriptEngine; +import org.renjin.sexp.DoubleArrayVector; + +/** + * Renjin showcase. + * + * @author Donato Rimenti + */ +public class RenjinMean { + + /** + * Invokes the customMean R function passing the given values as arguments. + * + * @param values the input to the mean script + * @return the result of the R script + * @throws IOException if any error occurs + * @throws URISyntaxException if any error occurs + * @throws ScriptException if any error occurs + */ + public double mean(int[] values) throws IOException, URISyntaxException, ScriptException { + RenjinScriptEngine engine = new RenjinScriptEngine(); + String meanScriptContent = RUtils.getMeanScriptContent(); + engine.put("input", values); + engine.eval(meanScriptContent); + DoubleArrayVector result = (DoubleArrayVector) engine.eval("customMean(input)"); + return result.asReal(); + } + +} \ No newline at end of file diff --git a/libraries-data-2/src/main/java/com/baeldung/r/RserveMean.java b/libraries-data-2/src/main/java/com/baeldung/r/RserveMean.java new file mode 100644 index 0000000000..51aaa90648 --- /dev/null +++ b/libraries-data-2/src/main/java/com/baeldung/r/RserveMean.java @@ -0,0 +1,29 @@ +package com.baeldung.r; + +import org.rosuda.REngine.REXPMismatchException; +import org.rosuda.REngine.REngineException; +import org.rosuda.REngine.Rserve.RConnection; + +/** + * Rserve showcase. + * + * @author Donato Rimenti + */ +public class RserveMean { + + /** + * Connects to the Rserve istance listening on 127.0.0.1:6311 and invokes the + * customMean R function passing the given values as arguments. + * + * @param values the input to the mean script + * @return the result of the R script + * @throws REngineException if any error occurs + * @throws REXPMismatchException if any error occurs + */ + public double mean(int[] values) throws REngineException, REXPMismatchException { + RConnection c = new RConnection(); + c.assign("input", values); + return c.eval("customMean(input)").asDouble(); + } + +} \ No newline at end of file diff --git a/libraries-data-2/src/test/java/com/baeldung/r/FastRMeanUnitTest.java b/libraries-data-2/src/test/java/com/baeldung/r/FastRMeanUnitTest.java new file mode 100644 index 0000000000..5cf8c63a56 --- /dev/null +++ b/libraries-data-2/src/test/java/com/baeldung/r/FastRMeanUnitTest.java @@ -0,0 +1,29 @@ +package com.baeldung.r; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +/** + * Test for {@link FastRMean}. + * + * @author Donato Rimenti + */ +@Ignore +public class FastRMeanUnitTest { + + /** + * Object to test. + */ + private FastRMean fastrMean = new FastRMean(); + + /** + * Test for {@link FastRMeanUnitTest#mean(int[])}. + */ + @Test + public void givenValues_whenMean_thenCorrect() { + int[] input = { 1, 2, 3, 4, 5 }; + double result = fastrMean.mean(input); + Assert.assertEquals(3.0, result, 0.000001); + } +} \ No newline at end of file diff --git a/libraries-data-2/src/test/java/com/baeldung/r/RCallerMeanIntegrationTest.java b/libraries-data-2/src/test/java/com/baeldung/r/RCallerMeanIntegrationTest.java new file mode 100644 index 0000000000..b68f259edd --- /dev/null +++ b/libraries-data-2/src/test/java/com/baeldung/r/RCallerMeanIntegrationTest.java @@ -0,0 +1,37 @@ +package com.baeldung.r; + +import java.io.IOException; +import java.net.URISyntaxException; + +import javax.script.ScriptException; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +/** + * Test for {@link RCallerMean}. + * + * @author Donato Rimenti + */ +@Ignore +public class RCallerMeanIntegrationTest { + + /** + * Object to test. + */ + private RCallerMean rcallerMean = new RCallerMean(); + + /** + * Test for {@link RCallerMeanIntegrationTest#mean(int[])}. + * + * @throws ScriptException if an error occurs + * @throws URISyntaxException if an error occurs + */ + @Test + public void givenValues_whenMean_thenCorrect() throws IOException, URISyntaxException { + int[] input = { 1, 2, 3, 4, 5 }; + double result = rcallerMean.mean(input); + Assert.assertEquals(3.0, result, 0.000001); + } +} \ No newline at end of file diff --git a/libraries-data-2/src/test/java/com/baeldung/r/RenjinMeanUnitTest.java b/libraries-data-2/src/test/java/com/baeldung/r/RenjinMeanUnitTest.java new file mode 100644 index 0000000000..e364d54632 --- /dev/null +++ b/libraries-data-2/src/test/java/com/baeldung/r/RenjinMeanUnitTest.java @@ -0,0 +1,37 @@ +package com.baeldung.r; + +import java.io.IOException; +import java.net.URISyntaxException; + +import javax.script.ScriptException; + +import org.junit.Test; + +import org.junit.Assert; + +/** + * Test for {@link RenjinMean}. + * + * @author Donato Rimenti + */ +public class RenjinMeanUnitTest { + + /** + * Object to test. + */ + private RenjinMean renjinMean = new RenjinMean(); + + /** + * Test for {@link RenjinMeanUnitTest#mean(int[])}. + * + * @throws ScriptException if an error occurs + * @throws URISyntaxException if an error occurs + * @throws IOException if an error occurs + */ + @Test + public void givenValues_whenMean_thenCorrect() throws IOException, URISyntaxException, ScriptException { + int[] input = { 1, 2, 3, 4, 5 }; + double result = renjinMean.mean(input); + Assert.assertEquals(3.0, result, 0.000001); + } +} \ No newline at end of file diff --git a/libraries-data-2/src/test/resources/script.R b/libraries-data-2/src/test/resources/script.R new file mode 100644 index 0000000000..08f859cc3d --- /dev/null +++ b/libraries-data-2/src/test/resources/script.R @@ -0,0 +1,3 @@ +customMean <- function(vector) { + mean(vector) +} \ No newline at end of file From 16ca52363cef9a05a32113654ae290854cb27866 Mon Sep 17 00:00:00 2001 From: Donato Rimenti Date: Mon, 20 Apr 2020 20:11:06 +0200 Subject: [PATCH 06/17] Fixed test exclusions and added missing tests. --- libraries-data-2/pom.xml | 5 ++- .../baeldung/r/RserveMeanIntegrationTest.java | 34 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 libraries-data-2/src/test/java/com/baeldung/r/RserveMeanIntegrationTest.java diff --git a/libraries-data-2/pom.xml b/libraries-data-2/pom.xml index ce15ef6c07..0dadcbd8d4 100644 --- a/libraries-data-2/pom.xml +++ b/libraries-data-2/pom.xml @@ -189,10 +189,13 @@ org.apache.maven.plugins maven-compiler-plugin - + com/baeldung/r/FastRMean.java + + com/baeldung/r/FastRMeanUnitTest.java + diff --git a/libraries-data-2/src/test/java/com/baeldung/r/RserveMeanIntegrationTest.java b/libraries-data-2/src/test/java/com/baeldung/r/RserveMeanIntegrationTest.java new file mode 100644 index 0000000000..95b344cb02 --- /dev/null +++ b/libraries-data-2/src/test/java/com/baeldung/r/RserveMeanIntegrationTest.java @@ -0,0 +1,34 @@ +package com.baeldung.r; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.rosuda.REngine.REXPMismatchException; +import org.rosuda.REngine.REngineException; + +/** + * Test for {@link RserveMean}. + * + * @author Donato Rimenti + */ +@Ignore +public class RserveMeanIntegrationTest { + + /** + * Object to test. + */ + private RserveMean rserveMean = new RserveMean(); + + /** + * Test for {@link RserveMeanIntegrationTest#mean(int[])}. + * + * @throws REXPMismatchException if an error occurs + * @throws REngineException if an error occurs + */ + @Test + public void givenValues_whenMean_thenCorrect() throws REngineException, REXPMismatchException { + int[] input = { 1, 2, 3, 4, 5 }; + double result = rserveMean.mean(input); + Assert.assertEquals(3.0, result, 0.000001); + } +} \ No newline at end of file From 64e47e7f77a887e29da95cc1443d66cddc9c73c6 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Tue, 21 Apr 2020 10:25:27 -0600 Subject: [PATCH 07/17] BAEL-3972: check user roles in Java --- .../app/controller/TaskController.java | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/controller/TaskController.java b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/controller/TaskController.java index a084f14eca..95f855c1e5 100644 --- a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/controller/TaskController.java +++ b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/controller/TaskController.java @@ -1,8 +1,15 @@ package com.baeldung.app.controller; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -10,6 +17,8 @@ import org.springframework.web.bind.annotation.RequestMethod; import com.baeldung.app.entity.Task; import com.baeldung.app.service.TaskService; +import javax.servlet.http.HttpServletRequest; + @Controller @RequestMapping("api/tasks") public class TaskController { @@ -17,6 +26,9 @@ public class TaskController { @Autowired private TaskService taskService; + @Autowired(required = false) + private UserDetailsService userDetailsService; + @RequestMapping(method = RequestMethod.GET) public ResponseEntity> findAllTasks() { Iterable tasks = taskService.findAll(); @@ -30,4 +42,66 @@ public class TaskController { return ResponseEntity.ok().body(tasks); } + + /** + * Example of restricting specific endpoints to specific roles using @PreAuthorize. + */ + @GetMapping("/manager") + @PreAuthorize("hasRole('ROLE_MANAGER')") + public ResponseEntity> getAlManagerTasks() + { + Iterable tasks = taskService.findAll(); + + return ResponseEntity.ok().body(tasks); + } + + /** + * Example of restricting specific endpoints to specific roles using SecurityContext. + */ + @GetMapping("/actuator") + public ResponseEntity> getAlActuatorTasks() + { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth != null && auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ACTUATOR"))) + { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + Iterable tasks = taskService.findAll(); + + return ResponseEntity.ok().body(tasks); + } + + /** + * Example of restricting specific endpoints to specific roles using UserDetailsService. + */ + @GetMapping("/admin") + public ResponseEntity> getAlAdminTasks() + { + if(userDetailsService != null) { + UserDetails details = userDetailsService.loadUserByUsername("pam"); + if (details != null && details.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ADMIN"))) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + } + + Iterable tasks = taskService.findAll(); + + return ResponseEntity.ok().body(tasks); + } + + /** + * Example of restricting specific endpoints to specific roles using HttpServletRequest. + */ + @GetMapping("/admin2") + public ResponseEntity> getAlAdminTasksUsingServlet(HttpServletRequest request) + { + if (!request.isUserInRole("ROLE_ADMIN")) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + Iterable tasks = taskService.findAll(); + + return ResponseEntity.ok().body(tasks); + } } From 553e4f1a0454f64390e5aeec4de6347a7a354ab7 Mon Sep 17 00:00:00 2001 From: Justin Albano Date: Tue, 21 Apr 2020 14:27:42 -0400 Subject: [PATCH 08/17] BAEL-3965: Moved examples to new spring-core module --- pom.xml | 2 + spring-core-4/README.md | 7 ++ spring-core-4/pom.xml | 88 +++++++++++++++++++ .../java/com/baeldung/factorymethod/Bar.java | 0 .../java/com/baeldung/factorymethod/Foo.java | 0 .../factorymethod/InstanceBarFactory.java | 0 .../factorymethod/InstanceFooFactory.java | 0 .../factorymethod/SingletonBarFactory.java | 0 .../factorymethod/SingletonFooFactory.java | 0 .../InstanceBarFactoryIntegrationTest.java | 0 .../InstanceFooFactoryIntegrationTest.java | 0 .../SingletonBarFactoryIntegrationTest.java | 0 .../SingletonFooFactoryIntegrationTest.java | 0 .../factorymethod/instance-bar-config.xml | 0 .../factorymethod/instance-foo-config.xml | 0 .../factorymethod/static-bar-config.xml | 18 ++-- .../factorymethod/static-foo-config.xml | 0 17 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 spring-core-4/README.md create mode 100644 spring-core-4/pom.xml rename {spring-core-3 => spring-core-4}/src/main/java/com/baeldung/factorymethod/Bar.java (100%) rename {spring-core-3 => spring-core-4}/src/main/java/com/baeldung/factorymethod/Foo.java (100%) rename {spring-core-3 => spring-core-4}/src/main/java/com/baeldung/factorymethod/InstanceBarFactory.java (100%) rename {spring-core-3 => spring-core-4}/src/main/java/com/baeldung/factorymethod/InstanceFooFactory.java (100%) rename {spring-core-3 => spring-core-4}/src/main/java/com/baeldung/factorymethod/SingletonBarFactory.java (100%) rename {spring-core-3 => spring-core-4}/src/main/java/com/baeldung/factorymethod/SingletonFooFactory.java (100%) rename {spring-core-3 => spring-core-4}/src/test/java/com/baeldung/factorymethod/InstanceBarFactoryIntegrationTest.java (100%) rename {spring-core-3 => spring-core-4}/src/test/java/com/baeldung/factorymethod/InstanceFooFactoryIntegrationTest.java (100%) rename {spring-core-3 => spring-core-4}/src/test/java/com/baeldung/factorymethod/SingletonBarFactoryIntegrationTest.java (100%) rename {spring-core-3 => spring-core-4}/src/test/java/com/baeldung/factorymethod/SingletonFooFactoryIntegrationTest.java (100%) rename {spring-core-3 => spring-core-4}/src/test/resources/factorymethod/instance-bar-config.xml (100%) rename {spring-core-3 => spring-core-4}/src/test/resources/factorymethod/instance-foo-config.xml (100%) rename {spring-core-3 => spring-core-4}/src/test/resources/factorymethod/static-bar-config.xml (54%) rename {spring-core-3 => spring-core-4}/src/test/resources/factorymethod/static-foo-config.xml (100%) diff --git a/pom.xml b/pom.xml index 9e3b354d74..ab6870c780 100644 --- a/pom.xml +++ b/pom.xml @@ -651,6 +651,7 @@ spring-core spring-core-2 spring-core-3 + spring-core-4 spring-cucumber spring-data-rest @@ -1155,6 +1156,7 @@ spring-core spring-core-2 spring-core-3 + spring-core-4 spring-cucumber spring-data-rest diff --git a/spring-core-4/README.md b/spring-core-4/README.md new file mode 100644 index 0000000000..f882c77179 --- /dev/null +++ b/spring-core-4/README.md @@ -0,0 +1,7 @@ +## Spring Core + +This module contains articles about core Spring functionality + +## Relevant Articles: + +- More articles: [[<-- prev]](/spring-core-3) diff --git a/spring-core-4/pom.xml b/spring-core-4/pom.xml new file mode 100644 index 0000000000..06598fb41e --- /dev/null +++ b/spring-core-4/pom.xml @@ -0,0 +1,88 @@ + + + 4.0.0 + spring-core-4 + spring-core-4 + + + com.baeldung + parent-spring-5 + 0.0.1-SNAPSHOT + ../parent-spring-5 + + + + + org.springframework + spring-beans + ${spring.version} + + + org.springframework + spring-tx + ${spring.version} + + + org.springframework + spring-jdbc + ${spring.version} + + + org.springframework.boot + spring-boot-starter-web + ${spring.boot.version} + + + org.springframework + spring-context + ${spring.version} + + + org.springframework + spring-core + ${spring.version} + + + javax.annotation + javax.annotation-api + ${annotation-api.version} + + + org.springframework + spring-test + ${spring.version} + test + + + org.junit.jupiter + junit-jupiter-engine + ${junit-jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-api + ${junit-jupiter.version} + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven.surefire.version} + + + + + + 2.22.1 + 1.3.2 + 2.2.2.RELEASE + + + \ No newline at end of file diff --git a/spring-core-3/src/main/java/com/baeldung/factorymethod/Bar.java b/spring-core-4/src/main/java/com/baeldung/factorymethod/Bar.java similarity index 100% rename from spring-core-3/src/main/java/com/baeldung/factorymethod/Bar.java rename to spring-core-4/src/main/java/com/baeldung/factorymethod/Bar.java diff --git a/spring-core-3/src/main/java/com/baeldung/factorymethod/Foo.java b/spring-core-4/src/main/java/com/baeldung/factorymethod/Foo.java similarity index 100% rename from spring-core-3/src/main/java/com/baeldung/factorymethod/Foo.java rename to spring-core-4/src/main/java/com/baeldung/factorymethod/Foo.java diff --git a/spring-core-3/src/main/java/com/baeldung/factorymethod/InstanceBarFactory.java b/spring-core-4/src/main/java/com/baeldung/factorymethod/InstanceBarFactory.java similarity index 100% rename from spring-core-3/src/main/java/com/baeldung/factorymethod/InstanceBarFactory.java rename to spring-core-4/src/main/java/com/baeldung/factorymethod/InstanceBarFactory.java diff --git a/spring-core-3/src/main/java/com/baeldung/factorymethod/InstanceFooFactory.java b/spring-core-4/src/main/java/com/baeldung/factorymethod/InstanceFooFactory.java similarity index 100% rename from spring-core-3/src/main/java/com/baeldung/factorymethod/InstanceFooFactory.java rename to spring-core-4/src/main/java/com/baeldung/factorymethod/InstanceFooFactory.java diff --git a/spring-core-3/src/main/java/com/baeldung/factorymethod/SingletonBarFactory.java b/spring-core-4/src/main/java/com/baeldung/factorymethod/SingletonBarFactory.java similarity index 100% rename from spring-core-3/src/main/java/com/baeldung/factorymethod/SingletonBarFactory.java rename to spring-core-4/src/main/java/com/baeldung/factorymethod/SingletonBarFactory.java diff --git a/spring-core-3/src/main/java/com/baeldung/factorymethod/SingletonFooFactory.java b/spring-core-4/src/main/java/com/baeldung/factorymethod/SingletonFooFactory.java similarity index 100% rename from spring-core-3/src/main/java/com/baeldung/factorymethod/SingletonFooFactory.java rename to spring-core-4/src/main/java/com/baeldung/factorymethod/SingletonFooFactory.java diff --git a/spring-core-3/src/test/java/com/baeldung/factorymethod/InstanceBarFactoryIntegrationTest.java b/spring-core-4/src/test/java/com/baeldung/factorymethod/InstanceBarFactoryIntegrationTest.java similarity index 100% rename from spring-core-3/src/test/java/com/baeldung/factorymethod/InstanceBarFactoryIntegrationTest.java rename to spring-core-4/src/test/java/com/baeldung/factorymethod/InstanceBarFactoryIntegrationTest.java diff --git a/spring-core-3/src/test/java/com/baeldung/factorymethod/InstanceFooFactoryIntegrationTest.java b/spring-core-4/src/test/java/com/baeldung/factorymethod/InstanceFooFactoryIntegrationTest.java similarity index 100% rename from spring-core-3/src/test/java/com/baeldung/factorymethod/InstanceFooFactoryIntegrationTest.java rename to spring-core-4/src/test/java/com/baeldung/factorymethod/InstanceFooFactoryIntegrationTest.java diff --git a/spring-core-3/src/test/java/com/baeldung/factorymethod/SingletonBarFactoryIntegrationTest.java b/spring-core-4/src/test/java/com/baeldung/factorymethod/SingletonBarFactoryIntegrationTest.java similarity index 100% rename from spring-core-3/src/test/java/com/baeldung/factorymethod/SingletonBarFactoryIntegrationTest.java rename to spring-core-4/src/test/java/com/baeldung/factorymethod/SingletonBarFactoryIntegrationTest.java diff --git a/spring-core-3/src/test/java/com/baeldung/factorymethod/SingletonFooFactoryIntegrationTest.java b/spring-core-4/src/test/java/com/baeldung/factorymethod/SingletonFooFactoryIntegrationTest.java similarity index 100% rename from spring-core-3/src/test/java/com/baeldung/factorymethod/SingletonFooFactoryIntegrationTest.java rename to spring-core-4/src/test/java/com/baeldung/factorymethod/SingletonFooFactoryIntegrationTest.java diff --git a/spring-core-3/src/test/resources/factorymethod/instance-bar-config.xml b/spring-core-4/src/test/resources/factorymethod/instance-bar-config.xml similarity index 100% rename from spring-core-3/src/test/resources/factorymethod/instance-bar-config.xml rename to spring-core-4/src/test/resources/factorymethod/instance-bar-config.xml diff --git a/spring-core-3/src/test/resources/factorymethod/instance-foo-config.xml b/spring-core-4/src/test/resources/factorymethod/instance-foo-config.xml similarity index 100% rename from spring-core-3/src/test/resources/factorymethod/instance-foo-config.xml rename to spring-core-4/src/test/resources/factorymethod/instance-foo-config.xml diff --git a/spring-core-3/src/test/resources/factorymethod/static-bar-config.xml b/spring-core-4/src/test/resources/factorymethod/static-bar-config.xml similarity index 54% rename from spring-core-3/src/test/resources/factorymethod/static-bar-config.xml rename to spring-core-4/src/test/resources/factorymethod/static-bar-config.xml index 4d1befc645..e709da36a1 100644 --- a/spring-core-3/src/test/resources/factorymethod/static-bar-config.xml +++ b/spring-core-4/src/test/resources/factorymethod/static-bar-config.xml @@ -1,9 +1,9 @@ - - - + + + \ No newline at end of file diff --git a/spring-core-3/src/test/resources/factorymethod/static-foo-config.xml b/spring-core-4/src/test/resources/factorymethod/static-foo-config.xml similarity index 100% rename from spring-core-3/src/test/resources/factorymethod/static-foo-config.xml rename to spring-core-4/src/test/resources/factorymethod/static-foo-config.xml From 56153d65d8134d26ef0f6a2a2759b822b3c6ca9f Mon Sep 17 00:00:00 2001 From: Justin Albano Date: Wed, 22 Apr 2020 06:18:31 -0400 Subject: [PATCH 09/17] BAEL-3965: Corrected XML formatting in code examples --- .../factorymethod/instance-bar-config.xml | 20 +++++++++--------- .../factorymethod/instance-foo-config.xml | 20 +++++++++--------- .../factorymethod/static-bar-config.xml | 21 ++++++++----------- .../factorymethod/static-foo-config.xml | 21 ++++++++----------- 4 files changed, 38 insertions(+), 44 deletions(-) diff --git a/spring-core-4/src/test/resources/factorymethod/instance-bar-config.xml b/spring-core-4/src/test/resources/factorymethod/instance-bar-config.xml index 40d2f33683..a4281aee4e 100644 --- a/spring-core-4/src/test/resources/factorymethod/instance-bar-config.xml +++ b/spring-core-4/src/test/resources/factorymethod/instance-bar-config.xml @@ -1,19 +1,19 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:util="http://www.springframework.org/schema/util" + xsi:schemaLocation=" + http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/util + http://www.springframework.org/schema/util/spring-util.xsd"> + class="com.baeldung.factorymethod.InstanceBarFactory" /> + factory-bean="instanceBarFactory" + factory-method="createInstance"> diff --git a/spring-core-4/src/test/resources/factorymethod/instance-foo-config.xml b/spring-core-4/src/test/resources/factorymethod/instance-foo-config.xml index c45bef6a85..0f21f06f5a 100644 --- a/spring-core-4/src/test/resources/factorymethod/instance-foo-config.xml +++ b/spring-core-4/src/test/resources/factorymethod/instance-foo-config.xml @@ -1,18 +1,18 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:util="http://www.springframework.org/schema/util" + xsi:schemaLocation=" + http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/util + http://www.springframework.org/schema/util/spring-util.xsd"> + class="com.baeldung.factorymethod.InstanceFooFactory" /> + factory-bean="instanceFooFactory" + factory-method="createInstance" /> \ No newline at end of file diff --git a/spring-core-4/src/test/resources/factorymethod/static-bar-config.xml b/spring-core-4/src/test/resources/factorymethod/static-bar-config.xml index e709da36a1..2cacc293bc 100644 --- a/spring-core-4/src/test/resources/factorymethod/static-bar-config.xml +++ b/spring-core-4/src/test/resources/factorymethod/static-bar-config.xml @@ -1,19 +1,16 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:util="http://www.springframework.org/schema/util" + xsi:schemaLocation=" + http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/util + http://www.springframework.org/schema/util/spring-util.xsd"> + class="com.baeldung.factorymethod.SingletonBarFactory" + factory-method="createInstance"> diff --git a/spring-core-4/src/test/resources/factorymethod/static-foo-config.xml b/spring-core-4/src/test/resources/factorymethod/static-foo-config.xml index 83e61a656c..ffe1480638 100644 --- a/spring-core-4/src/test/resources/factorymethod/static-foo-config.xml +++ b/spring-core-4/src/test/resources/factorymethod/static-foo-config.xml @@ -1,18 +1,15 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:util="http://www.springframework.org/schema/util" + xsi:schemaLocation=" + http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/util + http://www.springframework.org/schema/util/spring-util.xsd"> + class="com.baeldung.factorymethod.SingletonFooFactory" + factory-method="createInstance" /> \ No newline at end of file From 62842f97cf2c1e1ce1ba94c5505d769acb0632a6 Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Thu, 23 Apr 2020 13:10:29 +0530 Subject: [PATCH 10/17] JAVA-923: Migrate spring-data-dynamodb to parent-boot-2 --- persistence-modules/spring-data-dynamodb/pom.xml | 8 ++++---- .../spring/data/dynamodb/config/DynamoDBConfig.java | 4 ++-- .../data/dynamodb/repositories/ProductInfoRepository.java | 7 ++++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/persistence-modules/spring-data-dynamodb/pom.xml b/persistence-modules/spring-data-dynamodb/pom.xml index fceceb40ba..377e35b635 100644 --- a/persistence-modules/spring-data-dynamodb/pom.xml +++ b/persistence-modules/spring-data-dynamodb/pom.xml @@ -9,9 +9,9 @@ com.baeldung - parent-boot-1 + parent-boot-2 0.0.1-SNAPSHOT - ../../parent-boot-1 + ../../parent-boot-2 @@ -19,7 +19,7 @@ org.springframework.data spring-data-releasetrain - Hopper-SR10 + Lovelace-SR16 pom import @@ -174,7 +174,7 @@ com.baeldung.Application 4.3.4.RELEASE 4.5.2 - 4.4.1 + 5.1.0 1.11.64 3.3.7-1 1.0.392 diff --git a/persistence-modules/spring-data-dynamodb/src/main/java/com/baeldung/spring/data/dynamodb/config/DynamoDBConfig.java b/persistence-modules/spring-data-dynamodb/src/main/java/com/baeldung/spring/data/dynamodb/config/DynamoDBConfig.java index 9278c0a12e..7e97e6b383 100644 --- a/persistence-modules/spring-data-dynamodb/src/main/java/com/baeldung/spring/data/dynamodb/config/DynamoDBConfig.java +++ b/persistence-modules/spring-data-dynamodb/src/main/java/com/baeldung/spring/data/dynamodb/config/DynamoDBConfig.java @@ -44,8 +44,8 @@ public class DynamoDBConfig { return new BasicAWSCredentials(amazonAWSAccessKey, amazonAWSSecretKey); } - @Bean(name = "mvcHandlerMappingIntrospector") - public HandlerMappingIntrospector mvcHandlerMappingIntrospector() { + @Bean(name = "mvcHandlerMappingIntrospectorCustom") + public HandlerMappingIntrospector mvcHandlerMappingIntrospectorCustom() { return new HandlerMappingIntrospector(context); } } diff --git a/persistence-modules/spring-data-dynamodb/src/main/java/com/baeldung/spring/data/dynamodb/repositories/ProductInfoRepository.java b/persistence-modules/spring-data-dynamodb/src/main/java/com/baeldung/spring/data/dynamodb/repositories/ProductInfoRepository.java index da47f033b6..6e8b493c3b 100644 --- a/persistence-modules/spring-data-dynamodb/src/main/java/com/baeldung/spring/data/dynamodb/repositories/ProductInfoRepository.java +++ b/persistence-modules/spring-data-dynamodb/src/main/java/com/baeldung/spring/data/dynamodb/repositories/ProductInfoRepository.java @@ -1,12 +1,13 @@ package com.baeldung.spring.data.dynamodb.repositories; -import com.baeldung.spring.data.dynamodb.model.ProductInfo; +import java.util.Optional; + import org.socialsignin.spring.data.dynamodb.repository.EnableScan; import org.springframework.data.repository.CrudRepository; -import java.util.List; +import com.baeldung.spring.data.dynamodb.model.ProductInfo; @EnableScan public interface ProductInfoRepository extends CrudRepository { - List findById(String id); + Optional findById(String id); } From 7d6e096d28e9c1585f52bb464e9150ebbd2ca3b1 Mon Sep 17 00:00:00 2001 From: Donato Rimenti Date: Fri, 24 Apr 2020 16:51:50 +0200 Subject: [PATCH 11/17] Fixed whitespace formatting. --- libraries-data-2/pom.xml | 77 +++++++++---------- .../main/java/com/baeldung/r/FastRMean.java | 33 ++++---- .../main/java/com/baeldung/r/RCallerMean.java | 37 ++++----- .../src/main/java/com/baeldung/r/RUtils.java | 27 ++++--- .../main/java/com/baeldung/r/RenjinMean.java | 34 ++++---- .../main/java/com/baeldung/r/RserveMean.java | 29 +++---- .../com/baeldung/r/FastRMeanUnitTest.java | 26 +++---- .../r/RCallerMeanIntegrationTest.java | 32 ++++---- .../com/baeldung/r/RenjinMeanUnitTest.java | 34 ++++---- .../baeldung/r/RserveMeanIntegrationTest.java | 32 ++++---- 10 files changed, 184 insertions(+), 177 deletions(-) diff --git a/libraries-data-2/pom.xml b/libraries-data-2/pom.xml index 0dadcbd8d4..73c5452f77 100644 --- a/libraries-data-2/pom.xml +++ b/libraries-data-2/pom.xml @@ -128,24 +128,21 @@ ${awaitility.version} test - - - org.rosuda.REngine - Rserve - ${rserve.version} - - - - com.github.jbytecode - RCaller - ${rcaller.version} - - - - org.renjin - renjin-script-engine - ${renjin.version} - + + org.rosuda.REngine + Rserve + ${rserve.version} + + + com.github.jbytecode + RCaller + ${rcaller.version} + + + org.renjin + renjin-script-engine + ${renjin.version} + @@ -157,11 +154,11 @@ - - bedatadriven - bedatadriven public repo - https://nexus.bedatadriven.com/content/groups/public/ - + + bedatadriven + bedatadriven public repo + https://nexus.bedatadriven.com/content/groups/public/ + @@ -183,22 +180,22 @@ 1.8.1 - - - - org.apache.maven.plugins - maven-compiler-plugin - - - - com/baeldung/r/FastRMean.java - - - com/baeldung/r/FastRMeanUnitTest.java - - - - - + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + com/baeldung/r/FastRMean.java + + + com/baeldung/r/FastRMeanUnitTest.java + + + + + \ No newline at end of file diff --git a/libraries-data-2/src/main/java/com/baeldung/r/FastRMean.java b/libraries-data-2/src/main/java/com/baeldung/r/FastRMean.java index 52fb2d1506..8348bfa403 100644 --- a/libraries-data-2/src/main/java/com/baeldung/r/FastRMean.java +++ b/libraries-data-2/src/main/java/com/baeldung/r/FastRMean.java @@ -10,19 +10,24 @@ import java.net.URISyntaxException; */ public class FastRMean { - /** - * Invokes the customMean R function passing the given values as arguments. - * - * @param values the input to the mean script - * @return the result of the R script - */ - public double mean(int[] values) { - Context polyglot = Context.newBuilder().allowAllAccess(true).build(); - String meanScriptContent = RUtils.getMeanScriptContent(); - polyglot.eval("R", meanScriptContent); - Value rBindings = polyglot.getBindings("R"); - Value rInput = rBindings.getMember("c").execute(values); - return rBindings.getMember("customMean").execute(rInput).asDouble(); - } + /** + * Invokes the customMean R function passing the given values as arguments. + * + * @param values the input to the mean script + * @return the result of the R script + */ + public double mean(int[] values) { + Context polyglot = Context.newBuilder() + .allowAllAccess(true) + .build(); + String meanScriptContent = RUtils.getMeanScriptContent(); + polyglot.eval("R", meanScriptContent); + Value rBindings = polyglot.getBindings("R"); + Value rInput = rBindings.getMember("c") + .execute(values); + return rBindings.getMember("customMean") + .execute(rInput) + .asDouble(); + } } \ No newline at end of file diff --git a/libraries-data-2/src/main/java/com/baeldung/r/RCallerMean.java b/libraries-data-2/src/main/java/com/baeldung/r/RCallerMean.java index 53e0ab9e31..99edb8c043 100644 --- a/libraries-data-2/src/main/java/com/baeldung/r/RCallerMean.java +++ b/libraries-data-2/src/main/java/com/baeldung/r/RCallerMean.java @@ -14,23 +14,24 @@ import com.github.rcaller.rstuff.RCode; */ public class RCallerMean { - /** - * Invokes the customMean R function passing the given values as arguments. - * - * @param values the input to the mean script - * @return the result of the R script - * @throws IOException if any error occurs - * @throws URISyntaxException if any error occurs - */ - public double mean(int[] values) throws IOException, URISyntaxException { - String fileContent = RUtils.getMeanScriptContent(); - RCode code = RCode.create(); - code.addRCode(fileContent); - code.addIntArray("input", values); - code.addRCode("result <- customMean(input)"); - RCaller caller = RCaller.create(code, RCallerOptions.create()); - caller.runAndReturnResult("result"); - return caller.getParser().getAsDoubleArray("result")[0]; - } + /** + * Invokes the customMean R function passing the given values as arguments. + * + * @param values the input to the mean script + * @return the result of the R script + * @throws IOException if any error occurs + * @throws URISyntaxException if any error occurs + */ + public double mean(int[] values) throws IOException, URISyntaxException { + String fileContent = RUtils.getMeanScriptContent(); + RCode code = RCode.create(); + code.addRCode(fileContent); + code.addIntArray("input", values); + code.addRCode("result <- customMean(input)"); + RCaller caller = RCaller.create(code, RCallerOptions.create()); + caller.runAndReturnResult("result"); + return caller.getParser() + .getAsDoubleArray("result")[0]; + } } \ No newline at end of file diff --git a/libraries-data-2/src/main/java/com/baeldung/r/RUtils.java b/libraries-data-2/src/main/java/com/baeldung/r/RUtils.java index ad16fd5602..a9393cdcc2 100644 --- a/libraries-data-2/src/main/java/com/baeldung/r/RUtils.java +++ b/libraries-data-2/src/main/java/com/baeldung/r/RUtils.java @@ -15,16 +15,19 @@ import java.util.stream.Collectors; */ public class RUtils { - /** - * Loads the script.R and returns its content as a string. - * - * @return the script.R content as a string - * @throws IOException if any error occurs - * @throws URISyntaxException if any error occurs - */ - static String getMeanScriptContent() throws IOException, URISyntaxException { - URI rScriptUri = RUtils.class.getClassLoader().getResource("script.R").toURI(); - Path inputScript = Paths.get(rScriptUri); - return Files.lines(inputScript).collect(Collectors.joining()); - } + /** + * Loads the script.R and returns its content as a string. + * + * @return the script.R content as a string + * @throws IOException if any error occurs + * @throws URISyntaxException if any error occurs + */ + static String getMeanScriptContent() throws IOException, URISyntaxException { + URI rScriptUri = RUtils.class.getClassLoader() + .getResource("script.R") + .toURI(); + Path inputScript = Paths.get(rScriptUri); + return Files.lines(inputScript) + .collect(Collectors.joining()); + } } \ No newline at end of file diff --git a/libraries-data-2/src/main/java/com/baeldung/r/RenjinMean.java b/libraries-data-2/src/main/java/com/baeldung/r/RenjinMean.java index befb7d522f..4576ec5fb4 100644 --- a/libraries-data-2/src/main/java/com/baeldung/r/RenjinMean.java +++ b/libraries-data-2/src/main/java/com/baeldung/r/RenjinMean.java @@ -15,22 +15,22 @@ import org.renjin.sexp.DoubleArrayVector; */ public class RenjinMean { - /** - * Invokes the customMean R function passing the given values as arguments. - * - * @param values the input to the mean script - * @return the result of the R script - * @throws IOException if any error occurs - * @throws URISyntaxException if any error occurs - * @throws ScriptException if any error occurs - */ - public double mean(int[] values) throws IOException, URISyntaxException, ScriptException { - RenjinScriptEngine engine = new RenjinScriptEngine(); - String meanScriptContent = RUtils.getMeanScriptContent(); - engine.put("input", values); - engine.eval(meanScriptContent); - DoubleArrayVector result = (DoubleArrayVector) engine.eval("customMean(input)"); - return result.asReal(); - } + /** + * Invokes the customMean R function passing the given values as arguments. + * + * @param values the input to the mean script + * @return the result of the R script + * @throws IOException if any error occurs + * @throws URISyntaxException if any error occurs + * @throws ScriptException if any error occurs + */ + public double mean(int[] values) throws IOException, URISyntaxException, ScriptException { + RenjinScriptEngine engine = new RenjinScriptEngine(); + String meanScriptContent = RUtils.getMeanScriptContent(); + engine.put("input", values); + engine.eval(meanScriptContent); + DoubleArrayVector result = (DoubleArrayVector) engine.eval("customMean(input)"); + return result.asReal(); + } } \ No newline at end of file diff --git a/libraries-data-2/src/main/java/com/baeldung/r/RserveMean.java b/libraries-data-2/src/main/java/com/baeldung/r/RserveMean.java index 51aaa90648..1aaa7fa847 100644 --- a/libraries-data-2/src/main/java/com/baeldung/r/RserveMean.java +++ b/libraries-data-2/src/main/java/com/baeldung/r/RserveMean.java @@ -11,19 +11,20 @@ import org.rosuda.REngine.Rserve.RConnection; */ public class RserveMean { - /** - * Connects to the Rserve istance listening on 127.0.0.1:6311 and invokes the - * customMean R function passing the given values as arguments. - * - * @param values the input to the mean script - * @return the result of the R script - * @throws REngineException if any error occurs - * @throws REXPMismatchException if any error occurs - */ - public double mean(int[] values) throws REngineException, REXPMismatchException { - RConnection c = new RConnection(); - c.assign("input", values); - return c.eval("customMean(input)").asDouble(); - } + /** + * Connects to the Rserve istance listening on 127.0.0.1:6311 and invokes the + * customMean R function passing the given values as arguments. + * + * @param values the input to the mean script + * @return the result of the R script + * @throws REngineException if any error occurs + * @throws REXPMismatchException if any error occurs + */ + public double mean(int[] values) throws REngineException, REXPMismatchException { + RConnection c = new RConnection(); + c.assign("input", values); + return c.eval("customMean(input)") + .asDouble(); + } } \ No newline at end of file diff --git a/libraries-data-2/src/test/java/com/baeldung/r/FastRMeanUnitTest.java b/libraries-data-2/src/test/java/com/baeldung/r/FastRMeanUnitTest.java index 5cf8c63a56..4e7426b75a 100644 --- a/libraries-data-2/src/test/java/com/baeldung/r/FastRMeanUnitTest.java +++ b/libraries-data-2/src/test/java/com/baeldung/r/FastRMeanUnitTest.java @@ -12,18 +12,18 @@ import org.junit.Test; @Ignore public class FastRMeanUnitTest { - /** - * Object to test. - */ - private FastRMean fastrMean = new FastRMean(); + /** + * Object to test. + */ + private FastRMean fastrMean = new FastRMean(); - /** - * Test for {@link FastRMeanUnitTest#mean(int[])}. - */ - @Test - public void givenValues_whenMean_thenCorrect() { - int[] input = { 1, 2, 3, 4, 5 }; - double result = fastrMean.mean(input); - Assert.assertEquals(3.0, result, 0.000001); - } + /** + * Test for {@link FastRMeanUnitTest#mean(int[])}. + */ + @Test + public void givenValues_whenMean_thenCorrect() { + int[] input = { 1, 2, 3, 4, 5 }; + double result = fastrMean.mean(input); + Assert.assertEquals(3.0, result, 0.000001); + } } \ No newline at end of file diff --git a/libraries-data-2/src/test/java/com/baeldung/r/RCallerMeanIntegrationTest.java b/libraries-data-2/src/test/java/com/baeldung/r/RCallerMeanIntegrationTest.java index b68f259edd..ce6b3a4332 100644 --- a/libraries-data-2/src/test/java/com/baeldung/r/RCallerMeanIntegrationTest.java +++ b/libraries-data-2/src/test/java/com/baeldung/r/RCallerMeanIntegrationTest.java @@ -17,21 +17,21 @@ import org.junit.Test; @Ignore public class RCallerMeanIntegrationTest { - /** - * Object to test. - */ - private RCallerMean rcallerMean = new RCallerMean(); + /** + * Object to test. + */ + private RCallerMean rcallerMean = new RCallerMean(); - /** - * Test for {@link RCallerMeanIntegrationTest#mean(int[])}. - * - * @throws ScriptException if an error occurs - * @throws URISyntaxException if an error occurs - */ - @Test - public void givenValues_whenMean_thenCorrect() throws IOException, URISyntaxException { - int[] input = { 1, 2, 3, 4, 5 }; - double result = rcallerMean.mean(input); - Assert.assertEquals(3.0, result, 0.000001); - } + /** + * Test for {@link RCallerMeanIntegrationTest#mean(int[])}. + * + * @throws ScriptException if an error occurs + * @throws URISyntaxException if an error occurs + */ + @Test + public void givenValues_whenMean_thenCorrect() throws IOException, URISyntaxException { + int[] input = { 1, 2, 3, 4, 5 }; + double result = rcallerMean.mean(input); + Assert.assertEquals(3.0, result, 0.000001); + } } \ No newline at end of file diff --git a/libraries-data-2/src/test/java/com/baeldung/r/RenjinMeanUnitTest.java b/libraries-data-2/src/test/java/com/baeldung/r/RenjinMeanUnitTest.java index e364d54632..f52d37d614 100644 --- a/libraries-data-2/src/test/java/com/baeldung/r/RenjinMeanUnitTest.java +++ b/libraries-data-2/src/test/java/com/baeldung/r/RenjinMeanUnitTest.java @@ -16,22 +16,22 @@ import org.junit.Assert; */ public class RenjinMeanUnitTest { - /** - * Object to test. - */ - private RenjinMean renjinMean = new RenjinMean(); + /** + * Object to test. + */ + private RenjinMean renjinMean = new RenjinMean(); - /** - * Test for {@link RenjinMeanUnitTest#mean(int[])}. - * - * @throws ScriptException if an error occurs - * @throws URISyntaxException if an error occurs - * @throws IOException if an error occurs - */ - @Test - public void givenValues_whenMean_thenCorrect() throws IOException, URISyntaxException, ScriptException { - int[] input = { 1, 2, 3, 4, 5 }; - double result = renjinMean.mean(input); - Assert.assertEquals(3.0, result, 0.000001); - } + /** + * Test for {@link RenjinMeanUnitTest#mean(int[])}. + * + * @throws ScriptException if an error occurs + * @throws URISyntaxException if an error occurs + * @throws IOException if an error occurs + */ + @Test + public void givenValues_whenMean_thenCorrect() throws IOException, URISyntaxException, ScriptException { + int[] input = { 1, 2, 3, 4, 5 }; + double result = renjinMean.mean(input); + Assert.assertEquals(3.0, result, 0.000001); + } } \ No newline at end of file diff --git a/libraries-data-2/src/test/java/com/baeldung/r/RserveMeanIntegrationTest.java b/libraries-data-2/src/test/java/com/baeldung/r/RserveMeanIntegrationTest.java index 95b344cb02..23d42bd8e9 100644 --- a/libraries-data-2/src/test/java/com/baeldung/r/RserveMeanIntegrationTest.java +++ b/libraries-data-2/src/test/java/com/baeldung/r/RserveMeanIntegrationTest.java @@ -14,21 +14,21 @@ import org.rosuda.REngine.REngineException; @Ignore public class RserveMeanIntegrationTest { - /** - * Object to test. - */ - private RserveMean rserveMean = new RserveMean(); + /** + * Object to test. + */ + private RserveMean rserveMean = new RserveMean(); - /** - * Test for {@link RserveMeanIntegrationTest#mean(int[])}. - * - * @throws REXPMismatchException if an error occurs - * @throws REngineException if an error occurs - */ - @Test - public void givenValues_whenMean_thenCorrect() throws REngineException, REXPMismatchException { - int[] input = { 1, 2, 3, 4, 5 }; - double result = rserveMean.mean(input); - Assert.assertEquals(3.0, result, 0.000001); - } + /** + * Test for {@link RserveMeanIntegrationTest#mean(int[])}. + * + * @throws REXPMismatchException if an error occurs + * @throws REngineException if an error occurs + */ + @Test + public void givenValues_whenMean_thenCorrect() throws REngineException, REXPMismatchException { + int[] input = { 1, 2, 3, 4, 5 }; + double result = rserveMean.mean(input); + Assert.assertEquals(3.0, result, 0.000001); + } } \ No newline at end of file From fab18f2126b26d0dbe8f0e492e4d075f5a49bd57 Mon Sep 17 00:00:00 2001 From: sampadawagde Date: Sat, 25 Apr 2020 18:12:08 +0530 Subject: [PATCH 12/17] JAVA-926: Migrate spring-boot-custom-starter to parent-boot-2 --- .../test/java/{org => com}/baeldung/SpringContextTest.java | 0 .../greeter-spring-boot-sample-app/pom.xml | 4 ++-- .../test/java/{org => com}/baeldung/SpringContextTest.java | 0 .../spring-boot-custom-starter/greeter/pom.xml | 4 ++-- 4 files changed, 4 insertions(+), 4 deletions(-) rename spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-autoconfigure/src/test/java/{org => com}/baeldung/SpringContextTest.java (100%) rename spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/src/test/java/{org => com}/baeldung/SpringContextTest.java (100%) diff --git a/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-autoconfigure/src/test/java/org/baeldung/SpringContextTest.java b/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-autoconfigure/src/test/java/com/baeldung/SpringContextTest.java similarity index 100% rename from spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-autoconfigure/src/test/java/org/baeldung/SpringContextTest.java rename to spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-autoconfigure/src/test/java/com/baeldung/SpringContextTest.java diff --git a/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/pom.xml b/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/pom.xml index 818ce5c107..8d328b88be 100644 --- a/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/pom.xml +++ b/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/pom.xml @@ -8,9 +8,9 @@ com.baeldung - parent-boot-1 + parent-boot-2 0.0.1-SNAPSHOT - ../../../parent-boot-1 + ../../../parent-boot-2 diff --git a/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/src/test/java/org/baeldung/SpringContextTest.java b/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/src/test/java/com/baeldung/SpringContextTest.java similarity index 100% rename from spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/src/test/java/org/baeldung/SpringContextTest.java rename to spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/src/test/java/com/baeldung/SpringContextTest.java diff --git a/spring-boot-modules/spring-boot-custom-starter/greeter/pom.xml b/spring-boot-modules/spring-boot-custom-starter/greeter/pom.xml index 89119e2e99..47296990aa 100644 --- a/spring-boot-modules/spring-boot-custom-starter/greeter/pom.xml +++ b/spring-boot-modules/spring-boot-custom-starter/greeter/pom.xml @@ -8,9 +8,9 @@ com.baeldung - parent-boot-1 + parent-boot-2 0.0.1-SNAPSHOT - ../../../parent-boot-1 + ../../../parent-boot-2 \ No newline at end of file From bd9c4945f7c1e96a64c944414f23b055f8e49482 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Sat, 25 Apr 2020 11:37:01 -0600 Subject: [PATCH 13/17] BAEL-3972: Fix formatting --- .../com/baeldung/app/controller/TaskController.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/controller/TaskController.java b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/controller/TaskController.java index 95f855c1e5..67072b5d61 100644 --- a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/controller/TaskController.java +++ b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/controller/TaskController.java @@ -48,8 +48,7 @@ public class TaskController { */ @GetMapping("/manager") @PreAuthorize("hasRole('ROLE_MANAGER')") - public ResponseEntity> getAlManagerTasks() - { + public ResponseEntity> getAlManagerTasks() { Iterable tasks = taskService.findAll(); return ResponseEntity.ok().body(tasks); @@ -59,8 +58,7 @@ public class TaskController { * Example of restricting specific endpoints to specific roles using SecurityContext. */ @GetMapping("/actuator") - public ResponseEntity> getAlActuatorTasks() - { + public ResponseEntity> getAlActuatorTasks() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ACTUATOR"))) { @@ -76,8 +74,7 @@ public class TaskController { * Example of restricting specific endpoints to specific roles using UserDetailsService. */ @GetMapping("/admin") - public ResponseEntity> getAlAdminTasks() - { + public ResponseEntity> getAlAdminTasks() { if(userDetailsService != null) { UserDetails details = userDetailsService.loadUserByUsername("pam"); if (details != null && details.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ADMIN"))) { @@ -94,8 +91,7 @@ public class TaskController { * Example of restricting specific endpoints to specific roles using HttpServletRequest. */ @GetMapping("/admin2") - public ResponseEntity> getAlAdminTasksUsingServlet(HttpServletRequest request) - { + public ResponseEntity> getAlAdminTasksUsingServlet(HttpServletRequest request) { if (!request.isUserInRole("ROLE_ADMIN")) { return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); } From fd5fcf29c55e234cb26262edf42b2c55ea55e7ef Mon Sep 17 00:00:00 2001 From: Justin Albano Date: Sat, 25 Apr 2020 16:05:50 -0400 Subject: [PATCH 14/17] BAEL-3965: Removed unneeded dependencies --- spring-core-4/pom.xml | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/spring-core-4/pom.xml b/spring-core-4/pom.xml index 06598fb41e..53f7ca6912 100644 --- a/spring-core-4/pom.xml +++ b/spring-core-4/pom.xml @@ -14,26 +14,6 @@ - - org.springframework - spring-beans - ${spring.version} - - - org.springframework - spring-tx - ${spring.version} - - - org.springframework - spring-jdbc - ${spring.version} - - - org.springframework.boot - spring-boot-starter-web - ${spring.boot.version} - org.springframework spring-context @@ -44,11 +24,6 @@ spring-core ${spring.version} - - javax.annotation - javax.annotation-api - ${annotation-api.version} - org.springframework spring-test From ee898632d354bfeb972ba3a01217910834517535 Mon Sep 17 00:00:00 2001 From: Aaron Juarez Date: Sat, 25 Apr 2020 16:23:13 -0400 Subject: [PATCH 15/17] BAEL-3966: find object's class in Java (#9118) --- .../com/baeldung/objectclass/Borrower.java | 23 ++++++ .../java/com/baeldung/objectclass/Lender.java | 20 +++++ .../java/com/baeldung/objectclass/User.java | 12 +++ .../objectclass/CreditAppUnitTest.java | 74 +++++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 core-java-modules/core-java/src/main/java/com/baeldung/objectclass/Borrower.java create mode 100644 core-java-modules/core-java/src/main/java/com/baeldung/objectclass/Lender.java create mode 100644 core-java-modules/core-java/src/main/java/com/baeldung/objectclass/User.java create mode 100644 core-java-modules/core-java/src/test/java/com/baeldung/objectclass/CreditAppUnitTest.java diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/objectclass/Borrower.java b/core-java-modules/core-java/src/main/java/com/baeldung/objectclass/Borrower.java new file mode 100644 index 0000000000..62062aa7fc --- /dev/null +++ b/core-java-modules/core-java/src/main/java/com/baeldung/objectclass/Borrower.java @@ -0,0 +1,23 @@ +package com.baeldung.objectclass; + +import lombok.Data; + +@Data +public class Borrower extends User { + + private double totalLoanAmount; + + public double requestLoan(double amount) { + totalLoanAmount = amount; + return totalLoanAmount; + } + + public double increaseLoan(double increaseBy) { + return totalLoanAmount + increaseBy; + } + + public double payLoan(double amount) { + return totalLoanAmount - amount; + } + +} diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/objectclass/Lender.java b/core-java-modules/core-java/src/main/java/com/baeldung/objectclass/Lender.java new file mode 100644 index 0000000000..b45272cbb1 --- /dev/null +++ b/core-java-modules/core-java/src/main/java/com/baeldung/objectclass/Lender.java @@ -0,0 +1,20 @@ +package com.baeldung.objectclass; + +public class Lender extends User { + + private double totalInvestmentAmount; + + public double invest(double amount) { + totalInvestmentAmount = amount; + return totalInvestmentAmount; + } + + public double increaseInvestment(double increaseBy) { + return totalInvestmentAmount + increaseBy; + } + + public double collectDividends() { + return totalInvestmentAmount * 0.07; + } + +} diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/objectclass/User.java b/core-java-modules/core-java/src/main/java/com/baeldung/objectclass/User.java new file mode 100644 index 0000000000..b1f3887f2f --- /dev/null +++ b/core-java-modules/core-java/src/main/java/com/baeldung/objectclass/User.java @@ -0,0 +1,12 @@ +package com.baeldung.objectclass; + +import lombok.Data; + +@Data +public class User { + + private String firstName; + private String lastName; + + +} diff --git a/core-java-modules/core-java/src/test/java/com/baeldung/objectclass/CreditAppUnitTest.java b/core-java-modules/core-java/src/test/java/com/baeldung/objectclass/CreditAppUnitTest.java new file mode 100644 index 0000000000..8330ddbac5 --- /dev/null +++ b/core-java-modules/core-java/src/test/java/com/baeldung/objectclass/CreditAppUnitTest.java @@ -0,0 +1,74 @@ +package com.baeldung.objectclass; + +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.Test; + +public class CreditAppUnitTest { + + @Test + public void givenLender_whenInstanceOf_thenReturnTrue() { + User lender = new Lender(); + assertTrue(lender instanceof Lender); + assertTrue(lender instanceof User); + } + + @Test + public void givenUser_whenInstanceOfLender_thenDowncast() { + User user = new Lender(); + Lender lender = null; + + if(user instanceof Lender) { + lender = (Lender) user; + } + + assertNotNull(lender); + } + + @Test + public void givenUser_whenIsInstanceOfLender_thenDowncast() { + User user = new Lender(); + Lender lender = null; + + if(Lender.class.isInstance(user)) { + lender = (Lender) user; + } + + assertNotNull(lender); + } + + @Test + public void givenBorrower_whenLoanAmountIsDouble_thenRequestLoan() { + Borrower borrower = new Borrower(); + double amount = 100.0; + + //if(amount instanceof Double) // Compilation error, no autoboxing + if(Double.class.isInstance(amount)) { + borrower.requestLoan(amount); + } + assertEquals(100, borrower.getTotalLoanAmount()); + } + + @Test + public void givenBorrower_whenLoanAmountIsNotString_thenRequestLoan() { + Borrower borrower = new Borrower(); + Double amount = 100.0; + + //if(amount instanceof String) // Compilation error, incompatible operands + if(!String.class.isInstance(amount)) { + borrower.requestLoan(amount); + } + assertEquals(100, borrower.getTotalLoanAmount()); + } + + @Test + public void givenLender_whenGetClass_thenEqualsLenderType() { + User lender = new Lender(); + assertEquals(Lender.class, lender.getClass()); + assertNotEquals(User.class, lender.getClass()); + } + +} From b8d41e5613457b185324cc39630816d83ac1cf4f Mon Sep 17 00:00:00 2001 From: Vikas Rajput Date: Sun, 26 Apr 2020 11:51:21 +0530 Subject: [PATCH 16/17] Bael 3557 : renamed package name to more unique name - springwithgroovy (#9172) * BAEL-3557: Completed a simple web application in spring boot and groovy * BAEL-3557: renamed packagename from com.baeldung.app to more unique name - com.baeldung.springwithgroovy Co-authored-by: Vikas Ramsingh Rajput --- .../SpringBootGroovyApplication.groovy | 13 +++ .../controller/TodoController.groovy | 48 +++++++++ .../springwithgroovy/entity/Todo.groovy | 23 +++++ .../repository/TodoRepository.groovy | 9 ++ .../service/TodoService.groovy | 16 +++ .../service/impl/TodoServiceImpl.groovy | 40 ++++++++ .../springwithgroovy/TodoAppUnitTest.groovy | 97 +++++++++++++++++++ 7 files changed, 246 insertions(+) create mode 100644 spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/SpringBootGroovyApplication.groovy create mode 100644 spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/controller/TodoController.groovy create mode 100644 spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/entity/Todo.groovy create mode 100644 spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/repository/TodoRepository.groovy create mode 100644 spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/service/TodoService.groovy create mode 100644 spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/service/impl/TodoServiceImpl.groovy create mode 100644 spring-boot-groovy/src/test/groovy/com/baeldung/springwithgroovy/TodoAppUnitTest.groovy diff --git a/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/SpringBootGroovyApplication.groovy b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/SpringBootGroovyApplication.groovy new file mode 100644 index 0000000000..4912b75a66 --- /dev/null +++ b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/SpringBootGroovyApplication.groovy @@ -0,0 +1,13 @@ +package com.baeldung.springwithgroovy + +import org.springframework.boot.SpringApplication +import org.springframework.boot.autoconfigure.SpringBootApplication + +import com.baeldung.springwithgroovy.SpringBootGroovyApplication + +@SpringBootApplication +class SpringBootGroovyApplication { + static void main(String[] args) { + SpringApplication.run SpringBootGroovyApplication, args + } +} diff --git a/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/controller/TodoController.groovy b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/controller/TodoController.groovy new file mode 100644 index 0000000000..9c6aee20d3 --- /dev/null +++ b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/controller/TodoController.groovy @@ -0,0 +1,48 @@ +package com.baeldung.springwithgroovy.controller + +import org.springframework.beans.factory.annotation.Autowired +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.RequestMethod +import org.springframework.web.bind.annotation.RestController + +import com.baeldung.springwithgroovy.entity.Todo +import com.baeldung.springwithgroovy.service.TodoService + +@RestController +@RequestMapping('todo') +public class TodoController { + + @Autowired + TodoService todoService + + @GetMapping + List getAllTodoList(){ + todoService.findAll() + } + + @PostMapping + Todo saveTodo(@RequestBody Todo todo){ + todoService.saveTodo todo + } + + @PutMapping + Todo updateTodo(@RequestBody Todo todo){ + todoService.updateTodo todo + } + + @DeleteMapping('/{todoId}') + deleteTodo(@PathVariable Integer todoId){ + todoService.deleteTodo todoId + } + + @GetMapping('/{todoId}') + Todo getTodoById(@PathVariable Integer todoId){ + todoService.findById todoId + } +} \ No newline at end of file diff --git a/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/entity/Todo.groovy b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/entity/Todo.groovy new file mode 100644 index 0000000000..000d981701 --- /dev/null +++ b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/entity/Todo.groovy @@ -0,0 +1,23 @@ +package com.baeldung.springwithgroovy.entity + +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.Table + +@Entity +@Table(name = 'todo') +class Todo { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + Integer id + + @Column + String task + + @Column + Boolean isCompleted + +} diff --git a/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/repository/TodoRepository.groovy b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/repository/TodoRepository.groovy new file mode 100644 index 0000000000..eb58cc0791 --- /dev/null +++ b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/repository/TodoRepository.groovy @@ -0,0 +1,9 @@ +package com.baeldung.springwithgroovy.repository + +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +import com.baeldung.springwithgroovy.entity.Todo + +@Repository +interface TodoRepository extends JpaRepository {} \ No newline at end of file diff --git a/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/service/TodoService.groovy b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/service/TodoService.groovy new file mode 100644 index 0000000000..c57af34cde --- /dev/null +++ b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/service/TodoService.groovy @@ -0,0 +1,16 @@ +package com.baeldung.springwithgroovy.service + +import com.baeldung.springwithgroovy.entity.Todo + +interface TodoService { + + List findAll() + + Todo findById(Integer todoId) + + Todo saveTodo(Todo todo) + + Todo updateTodo(Todo todo) + + Todo deleteTodo(Integer todoId) +} diff --git a/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/service/impl/TodoServiceImpl.groovy b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/service/impl/TodoServiceImpl.groovy new file mode 100644 index 0000000000..943c1c6944 --- /dev/null +++ b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/service/impl/TodoServiceImpl.groovy @@ -0,0 +1,40 @@ +package com.baeldung.springwithgroovy.service.impl + +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service + +import com.baeldung.springwithgroovy.entity.Todo +import com.baeldung.springwithgroovy.repository.TodoRepository +import com.baeldung.springwithgroovy.service.TodoService + +@Service +class TodoServiceImpl implements TodoService { + + @Autowired + TodoRepository todoRepository + + @Override + List findAll() { + todoRepository.findAll() + } + + @Override + Todo findById(Integer todoId) { + todoRepository.findById todoId get() + } + + @Override + Todo saveTodo(Todo todo){ + todoRepository.save todo + } + + @Override + Todo updateTodo(Todo todo){ + todoRepository.save todo + } + + @Override + Todo deleteTodo(Integer todoId){ + todoRepository.deleteById todoId + } +} diff --git a/spring-boot-groovy/src/test/groovy/com/baeldung/springwithgroovy/TodoAppUnitTest.groovy b/spring-boot-groovy/src/test/groovy/com/baeldung/springwithgroovy/TodoAppUnitTest.groovy new file mode 100644 index 0000000000..bf8b0ff27f --- /dev/null +++ b/spring-boot-groovy/src/test/groovy/com/baeldung/springwithgroovy/TodoAppUnitTest.groovy @@ -0,0 +1,97 @@ +package com.baeldung.springwithgroovy + +import static org.junit.jupiter.api.Assertions.assertEquals +import static org.junit.jupiter.api.Assertions.assertTrue + +import org.junit.BeforeClass +import org.junit.Test +import org.junit.runner.RunWith +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.test.context.event.annotation.BeforeTestClass +import org.springframework.test.context.junit4.SpringRunner + +import com.baeldung.springwithgroovy.entity.Todo + +import io.restassured.RestAssured +import io.restassured.response.Response + +class TodoAppUnitTest { + static API_ROOT = 'http://localhost:8081/todo' + static readingTodoId + static writingTodoId + + @BeforeClass + static void populateDummyData() { + Todo readingTodo = new Todo(task: 'Reading', isCompleted: false) + Todo writingTodo = new Todo(task: 'Writing', isCompleted: false) + + final Response readingResponse = + RestAssured.given() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .body(readingTodo).post(API_ROOT) + + Todo cookingTodoResponse = readingResponse.as Todo.class + readingTodoId = cookingTodoResponse.getId() + + final Response writingResponse = + RestAssured.given() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .body(writingTodo).post(API_ROOT) + + Todo writingTodoResponse = writingResponse.as Todo.class + writingTodoId = writingTodoResponse.getId() + } + + @Test + void whenGetAllTodoList_thenOk(){ + final Response response = RestAssured.get(API_ROOT) + + assertEquals HttpStatus.OK.value(),response.getStatusCode() + assertTrue response.as(List.class).size() > 0 + } + + @Test + void whenGetTodoById_thenOk(){ + final Response response = + RestAssured.get("$API_ROOT/$readingTodoId") + + assertEquals HttpStatus.OK.value(),response.getStatusCode() + Todo todoResponse = response.as Todo.class + assertEquals readingTodoId,todoResponse.getId() + } + + @Test + void whenUpdateTodoById_thenOk(){ + Todo todo = new Todo(id:readingTodoId, isCompleted: true) + final Response response = + RestAssured.given() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .body(todo).put(API_ROOT) + + assertEquals HttpStatus.OK.value(),response.getStatusCode() + Todo todoResponse = response.as Todo.class + assertTrue todoResponse.getIsCompleted() + } + + @Test + void whenDeleteTodoById_thenOk(){ + final Response response = + RestAssured.given() + .delete("$API_ROOT/$writingTodoId") + + assertEquals HttpStatus.OK.value(),response.getStatusCode() + } + + @Test + void whenSaveTodo_thenOk(){ + Todo todo = new Todo(task: 'Blogging', isCompleted: false) + final Response response = + RestAssured.given() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .body(todo).post(API_ROOT) + + assertEquals HttpStatus.OK.value(),response.getStatusCode() + } +} \ No newline at end of file From df179d642e3fef9da586f8fe2582fa6719d2fe53 Mon Sep 17 00:00:00 2001 From: Sampada <46674082+sampada07@users.noreply.github.com> Date: Sun, 26 Apr 2020 21:25:43 +0530 Subject: [PATCH 17/17] BAEL-3988: Calling a SOAP web service in Java (#9184) * BAEL-3988: Calling a SOAP web service in Java * BAEL-3988: modified generated class as per wsdl location change --- jee-7/pom.xml | 7 ++-- .../generated/CountryServiceImplService.java | 6 +-- jee-7/src/main/resources/country.wsdl | 40 ------------------- 3 files changed, 6 insertions(+), 47 deletions(-) delete mode 100644 jee-7/src/main/resources/country.wsdl diff --git a/jee-7/pom.xml b/jee-7/pom.xml index 7352c6550a..9077aae1a6 100644 --- a/jee-7/pom.xml +++ b/jee-7/pom.xml @@ -256,10 +256,9 @@ - src/main/resources - - country.wsdl - + + http://localhost:8888/ws/country?wsdl + true com.baeldung.soap.ws.client.generated src/main/java diff --git a/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/CountryServiceImplService.java b/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/CountryServiceImplService.java index 09f4c29202..a6983938f5 100644 --- a/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/CountryServiceImplService.java +++ b/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/CountryServiceImplService.java @@ -12,11 +12,11 @@ import javax.xml.ws.WebServiceFeature; /** * This class was generated by the JAX-WS RI. - * JAX-WS RI 2.3.2 + * JAX-WS RI 2.2.9-b130926.1035 * Generated source version: 2.2 * */ -@WebServiceClient(name = "CountryServiceImplService", targetNamespace = "http://server.ws.soap.baeldung.com/", wsdlLocation = "file:src/main/resources/country.wsdl") +@WebServiceClient(name = "CountryServiceImplService", targetNamespace = "http://server.ws.soap.baeldung.com/", wsdlLocation = "http://localhost:8888/ws/country?wsdl") public class CountryServiceImplService extends Service { private final static URL COUNTRYSERVICEIMPLSERVICE_WSDL_LOCATION; @@ -27,7 +27,7 @@ public class CountryServiceImplService extends Service { URL url = null; WebServiceException e = null; try { - url = new URL("file:src/main/resources/country.wsdl"); + url = new URL("http://localhost:8888/ws/country?wsdl"); } catch (MalformedURLException ex) { e = new WebServiceException(ex); } diff --git a/jee-7/src/main/resources/country.wsdl b/jee-7/src/main/resources/country.wsdl deleted file mode 100644 index 4d41fce322..0000000000 --- a/jee-7/src/main/resources/country.wsdl +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file