diff --git a/libraries-7/README.md b/libraries-7/README.md index 105a2ef16d..c56d52aa3e 100644 --- a/libraries-7/README.md +++ b/libraries-7/README.md @@ -8,4 +8,5 @@ The code examples related to different libraries are each in their own module. Remember, for advanced libraries like [Jackson](/jackson) and [JUnit](/testing-modules) we already have separate modules. Please make sure to have a look at the existing modules in such cases. ### Relevant articles +- [Find Files by Extension in Specified Directory in Java](https://www.baeldung.com/java-recursive-search-directory-extension-match) - More articles [[<-- prev]](/libraries-6) diff --git a/libraries-security/pom.xml b/libraries-security/pom.xml index 8a6dad6da2..8957996bad 100644 --- a/libraries-security/pom.xml +++ b/libraries-security/pom.xml @@ -9,9 +9,9 @@ com.baeldung - parent-boot-2 + parent-boot-3 0.0.1-SNAPSHOT - ../parent-boot-2 + ../parent-boot-3 @@ -20,9 +20,8 @@ spring-boot-starter-web - org.springframework.security.oauth - spring-security-oauth2 - ${spring-security-oauth2.version} + org.springframework.boot + spring-boot-starter-oauth2-resource-server org.springframework @@ -68,6 +67,29 @@ jsch ${jsch.version} + + com.sun.xml.bind + jaxb-core + 2.3.0.1 + runtime + + + javax.xml.bind + jaxb-api + 2.3.1 + runtime + + + com.sun.xml.bind + jaxb-impl + 2.3.1 + runtime + + + org.springframework.security + spring-security-oauth2-authorization-server + 1.2.1 + org.apache.sshd sshd-core @@ -125,7 +147,6 @@ 1.68 0.1.55 2.5.1 - 2.4.0.RELEASE 1.4.0 diff --git a/libraries-security/src/main/java/com/baeldung/scribejava/ScribejavaApplication.java b/libraries-security/src/main/java/com/baeldung/scribejava/ScribejavaApplication.java index 5b18567b2d..a5ff601ff5 100644 --- a/libraries-security/src/main/java/com/baeldung/scribejava/ScribejavaApplication.java +++ b/libraries-security/src/main/java/com/baeldung/scribejava/ScribejavaApplication.java @@ -4,7 +4,6 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; - @SpringBootApplication @ServletComponentScan public class ScribejavaApplication { @@ -13,5 +12,4 @@ public class ScribejavaApplication { SpringApplication.run(ScribejavaApplication.class, args); } - } diff --git a/libraries-security/src/main/java/com/baeldung/scribejava/controller/GoogleController.java b/libraries-security/src/main/java/com/baeldung/scribejava/controller/GoogleController.java index ffe4f0cc8a..4c63c70ef1 100644 --- a/libraries-security/src/main/java/com/baeldung/scribejava/controller/GoogleController.java +++ b/libraries-security/src/main/java/com/baeldung/scribejava/controller/GoogleController.java @@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; @RestController public class GoogleController { diff --git a/libraries-security/src/main/java/com/baeldung/scribejava/controller/RBACController.java b/libraries-security/src/main/java/com/baeldung/scribejava/controller/RBACController.java index 785f6228e8..0e747e2a22 100644 --- a/libraries-security/src/main/java/com/baeldung/scribejava/controller/RBACController.java +++ b/libraries-security/src/main/java/com/baeldung/scribejava/controller/RBACController.java @@ -2,15 +2,14 @@ package com.baeldung.scribejava.controller; import java.io.IOException; -import javax.annotation.security.DeclareRoles; -import javax.annotation.security.RolesAllowed; -import javax.servlet.ServletException; -import javax.servlet.annotation.HttpConstraint; -import javax.servlet.annotation.ServletSecurity; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.annotation.security.DeclareRoles; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.HttpConstraint; +import jakarta.servlet.annotation.ServletSecurity; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; @WebServlet(name="rbac", urlPatterns = {"/protected"}) @DeclareRoles("USER") diff --git a/libraries-security/src/main/java/com/baeldung/scribejava/controller/TwitterController.java b/libraries-security/src/main/java/com/baeldung/scribejava/controller/TwitterController.java index bfcd6d960c..792b6f7020 100644 --- a/libraries-security/src/main/java/com/baeldung/scribejava/controller/TwitterController.java +++ b/libraries-security/src/main/java/com/baeldung/scribejava/controller/TwitterController.java @@ -6,7 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Scanner; import java.util.concurrent.ExecutionException; diff --git a/libraries-security/src/main/java/com/baeldung/scribejava/controller/UserController.java b/libraries-security/src/main/java/com/baeldung/scribejava/controller/UserController.java index 68a11250de..62aac896fc 100644 --- a/libraries-security/src/main/java/com/baeldung/scribejava/controller/UserController.java +++ b/libraries-security/src/main/java/com/baeldung/scribejava/controller/UserController.java @@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import java.security.Principal; @RestController(value = "/user") diff --git a/libraries-security/src/main/java/com/baeldung/scribejava/oauth/AuthServiceConfig.java b/libraries-security/src/main/java/com/baeldung/scribejava/oauth/AuthServiceConfig.java index 2c7162399b..498b258011 100644 --- a/libraries-security/src/main/java/com/baeldung/scribejava/oauth/AuthServiceConfig.java +++ b/libraries-security/src/main/java/com/baeldung/scribejava/oauth/AuthServiceConfig.java @@ -1,45 +1,103 @@ package com.baeldung.scribejava.oauth; +import java.util.UUID; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; -import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; -import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; -import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; - +import org.springframework.core.annotation.Order; +import org.springframework.http.MediaType; +import org.springframework.security.config.Customizer; +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.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; +import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration; +import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer; +import org.springframework.security.oauth2.server.authorization.settings.ClientSettings; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; +import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher; @Configuration -@EnableAuthorizationServer -public class AuthServiceConfig extends AuthorizationServerConfigurerAdapter { +@EnableWebSecurity +public class AuthServiceConfig { - @Autowired - @Qualifier("authenticationManagerBean") - private AuthenticationManager authenticationManager; - - @Override - public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { - oauthServer.tokenKeyAccess("permitAll()") - .checkTokenAccess("isAuthenticated()"); + @Bean + public SecurityFilterChain securityFilter(HttpSecurity http) throws Exception { + http.headers( it -> it.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) + .csrf(AbstractHttpConfigurer::disable); + return http.build(); } - @Override - public void configure(ClientDetailsServiceConfigurer clients) throws Exception { - clients.inMemory() - .withClient("baeldung_api_key") - .secret("baeldung_api_secret") - .authorizedGrantTypes("password","refresh_token") - .scopes("read","write").autoApprove(true); + @Bean + public InMemoryUserDetailsManager userDetailsService() { + UserDetails user = User.withUsername("baeldung") + .password("scribejava") + .roles("USER") + .build(); + + return new InMemoryUserDetailsManager(user); + } + @Bean + public RegisteredClientRepository registeredClientRepository() { + RegisteredClient oidcClient = RegisteredClient.withId(UUID.randomUUID().toString()) + .clientId("baeldung_api_key") + .clientSecret("baeldung_api_secret") + .authorizationGrantType(AuthorizationGrantType.PASSWORD) + .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) + .scope("read") + .scope("write") + .clientSettings(ClientSettings.builder().requireAuthorizationConsent(false).build()) + .build(); + + return new InMemoryRegisteredClientRepository(oidcClient); } - @Override - public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { - endpoints - .authenticationManager(authenticationManager) - .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST); + @Bean + @Order(1) + public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception { + OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); + http.getConfigurer(OAuth2AuthorizationServerConfigurer.class) + .oidc(Customizer.withDefaults()); // Enable OpenID Connect 1.0 + http + // Redirect to the login page when not authenticated from the + // authorization endpoint + .exceptionHandling((exceptions) -> exceptions + .defaultAuthenticationEntryPointFor( + new LoginUrlAuthenticationEntryPoint("/login"), + new MediaTypeRequestMatcher(MediaType.TEXT_HTML) + ) + ) + // Accept access tokens for User Info and/or Client Registration + .oauth2ResourceServer((resourceServer) -> resourceServer + .jwt(Customizer.withDefaults())); + + return http.build(); } + @Bean + @Order(2) + public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) + throws Exception { + http + .authorizeHttpRequests((authorize) -> authorize + .anyRequest().authenticated() + ) + // Form login handles the redirect to the login page from the + // authorization server filter chain + .formLogin(Customizer.withDefaults()); + + return http.build(); + } + + } diff --git a/libraries-security/src/main/java/com/baeldung/scribejava/oauth/WebSecurityConfig.java b/libraries-security/src/main/java/com/baeldung/scribejava/oauth/WebSecurityConfig.java deleted file mode 100644 index 7aa51400ea..0000000000 --- a/libraries-security/src/main/java/com/baeldung/scribejava/oauth/WebSecurityConfig.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.baeldung.scribejava.oauth; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.authentication.AuthenticationManager; -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.WebSecurityConfigurerAdapter; -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; -import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; - -@Configuration -@EnableResourceServer -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .headers().frameOptions().disable() - .and() - .csrf().disable(); - } - - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.inMemoryAuthentication() - .withUser("baeldung") - .password("scribejava") - .roles("USER"); - } - - @Override - @Bean - public AuthenticationManager authenticationManagerBean() throws Exception { - return super.authenticationManagerBean(); - } - - - @EnableResourceServer - @Configuration - public class ResourceServerConfig extends ResourceServerConfigurerAdapter { - - @Override - public void configure(HttpSecurity http) throws Exception { - http - .authorizeRequests() - .antMatchers("/user/me").authenticated() - .and() - .csrf().disable(); - } - } - -} diff --git a/libraries-security/src/main/java/com/baeldung/scribejava/service/GoogleService.java b/libraries-security/src/main/java/com/baeldung/scribejava/service/GoogleService.java index fbcc39763c..497d6d469b 100644 --- a/libraries-security/src/main/java/com/baeldung/scribejava/service/GoogleService.java +++ b/libraries-security/src/main/java/com/baeldung/scribejava/service/GoogleService.java @@ -5,7 +5,7 @@ import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.core.oauth.OAuth20Service; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; @Component public class GoogleService { diff --git a/libraries-security/src/main/java/com/baeldung/scribejava/service/MyService.java b/libraries-security/src/main/java/com/baeldung/scribejava/service/MyService.java index 739c82172c..4397c8c7b6 100644 --- a/libraries-security/src/main/java/com/baeldung/scribejava/service/MyService.java +++ b/libraries-security/src/main/java/com/baeldung/scribejava/service/MyService.java @@ -5,7 +5,7 @@ import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.core.oauth.OAuth20Service; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; @Component public class MyService { diff --git a/libraries-security/src/main/java/com/baeldung/scribejava/service/TwitterService.java b/libraries-security/src/main/java/com/baeldung/scribejava/service/TwitterService.java index df49f74679..c09bdf98d3 100644 --- a/libraries-security/src/main/java/com/baeldung/scribejava/service/TwitterService.java +++ b/libraries-security/src/main/java/com/baeldung/scribejava/service/TwitterService.java @@ -5,7 +5,7 @@ import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.core.oauth.OAuth10aService; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; @Component public class TwitterService { diff --git a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/CustomClassIntegrationTest.java b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/CustomClassIntegrationTest.java index 699890c457..56165d7880 100644 --- a/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/CustomClassIntegrationTest.java +++ b/persistence-modules/hibernate-mapping/src/test/java/com/baeldung/hibernate/CustomClassIntegrationTest.java @@ -1,5 +1,6 @@ package com.baeldung.hibernate; +import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; @@ -74,5 +75,13 @@ public class CustomClassIntegrationTest { assertEquals("Sales", result.getDepartmentName()); } + @Test + public void whenCastResultQueryToList_ThenListOfResultIsReturned() { + Query query = session.createQuery("select new com.baeldung.hibernate.pojo.Result(m.name, m.department.name) " + + "from DeptEmployee m"); + List results = query.list(); + assertNotNull(results); + assertEquals(1, results.size()); + } } diff --git a/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/ApplicationConfig.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/ApplicationConfig.java new file mode 100644 index 0000000000..043efc584a --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/ApplicationConfig.java @@ -0,0 +1,8 @@ +package com.baeldung.spring.data.persistence.findvsget; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ApplicationConfig { + +} diff --git a/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/entity/User.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/entity/User.java new file mode 100644 index 0000000000..264ea92a5c --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/entity/User.java @@ -0,0 +1,90 @@ +package com.baeldung.spring.data.persistence.findvsget.entity; + +import java.util.Objects; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "users") +public class User { + + @Id + @Column(name = "id") + private Long id; + @Column(name = "first_name") + private String firstName; + @Column(name = "second_name") + private String secondName; + + public User() { + } + + public User(final Long id, final String firstName, final String secondName) { + this.id = id; + this.firstName = firstName; + this.secondName = secondName; + } + + public void setId(final Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(final String firstName) { + this.firstName = firstName; + } + + public String getSecondName() { + return secondName; + } + + public void setSecondName(final String secondName) { + this.secondName = secondName; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final User user = (User) o; + + if (!Objects.equals(id, user.id)) { + return false; + } + if (!Objects.equals(firstName, user.firstName)) { + return false; + } + return Objects.equals(secondName, user.secondName); + } + + @Override + public int hashCode() { + int result = id != null ? id.hashCode() : 0; + result = 31 * result + (firstName != null ? firstName.hashCode() : 0); + result = 31 * result + (secondName != null ? secondName.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "User{" + + "id=" + id + + ", firstName='" + firstName + '\'' + + ", secondName='" + secondName + '\'' + + '}'; + } +} diff --git a/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/repository/NewTransactionUserRepository.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/repository/NewTransactionUserRepository.java new file mode 100644 index 0000000000..6b0523b637 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/repository/NewTransactionUserRepository.java @@ -0,0 +1,19 @@ +package com.baeldung.spring.data.persistence.findvsget.repository; + +import com.baeldung.spring.data.persistence.findvsget.entity.User; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +@Repository +public interface NewTransactionUserRepository extends JpaRepository { + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + User getReferenceById(Long id); + + @Override + Optional findById(Long id); +} diff --git a/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/repository/SimpleUserRepository.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/repository/SimpleUserRepository.java new file mode 100644 index 0000000000..e105f226a5 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/repository/SimpleUserRepository.java @@ -0,0 +1,10 @@ +package com.baeldung.spring.data.persistence.findvsget.repository; + +import com.baeldung.spring.data.persistence.findvsget.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface SimpleUserRepository extends JpaRepository { + +} diff --git a/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/service/NonTransactionalUserReferenceService.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/service/NonTransactionalUserReferenceService.java new file mode 100644 index 0000000000..e79df3c91d --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/service/NonTransactionalUserReferenceService.java @@ -0,0 +1,33 @@ +package com.baeldung.spring.data.persistence.findvsget.service; + +import com.baeldung.spring.data.persistence.findvsget.entity.User; +import com.baeldung.spring.data.persistence.findvsget.repository.SimpleUserRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +@Service +public class NonTransactionalUserReferenceService { + + private static final Logger log = LoggerFactory.getLogger(NonTransactionalUserReferenceService.class); + private SimpleUserRepository repository; + + public User findUserReference(final long id) { + log.info("Before requesting a user"); + final User user = repository.getReferenceById(id); + log.info("After requesting a user"); + return user; + } + + public User findAndUseUserReference(final long id) { + final User user = repository.getReferenceById(id); + log.info("Before accessing a username"); + final String firstName = user.getFirstName(); + log.info("This message shouldn't be displayed because of the thrown exception: {}", firstName); + return user; + } + + public void setRepository(final SimpleUserRepository repository) { + this.repository = repository; + } +} diff --git a/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/service/SimpleUserService.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/service/SimpleUserService.java new file mode 100644 index 0000000000..0ed7a72946 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/service/SimpleUserService.java @@ -0,0 +1,28 @@ +package com.baeldung.spring.data.persistence.findvsget.service; + +import com.baeldung.spring.data.persistence.findvsget.entity.User; +import com.baeldung.spring.data.persistence.findvsget.repository.SimpleUserRepository; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +@Service +public class SimpleUserService { + + private static final Logger log = LoggerFactory.getLogger(SimpleUserService.class); + private final SimpleUserRepository repository; + + public SimpleUserService(final SimpleUserRepository repository) { + this.repository = repository; + } + + public User findUser(final long id) { + log.info("Before requesting a user in a findUser method"); + final Optional optionalUser = repository.findById(id); + log.info("After requesting a user in a findUser method"); + final User user = optionalUser.orElse(null); + log.info("After unwrapping an optional in a findUser method"); + return user; + } +} diff --git a/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/service/TransactionalUserReferenceService.java b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/service/TransactionalUserReferenceService.java new file mode 100644 index 0000000000..56ba884fed --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-4/src/main/java/com/baeldung/spring/data/persistence/findvsget/service/TransactionalUserReferenceService.java @@ -0,0 +1,36 @@ +package com.baeldung.spring.data.persistence.findvsget.service; + +import com.baeldung.spring.data.persistence.findvsget.entity.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class TransactionalUserReferenceService { + + private static final Logger log = LoggerFactory.getLogger(TransactionalUserReferenceService.class); + private JpaRepository repository; + + @Transactional + public User findUserReference(final long id) { + log.info("Before requesting a user"); + final User user = repository.getReferenceById(id); + log.info("After requesting a user"); + return user; + } + + @Transactional + public User findAndUseUserReference(final long id) { + final User user = repository.getReferenceById(id); + log.info("Before accessing a username"); + final String firstName = user.getFirstName(); + log.info("After accessing a username: {}", firstName); + return user; + } + + public void setRepository(final JpaRepository repository) { + this.repository = repository; + } +} diff --git a/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/findvsget/DatabaseConfigurationBaseIntegrationTest.java b/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/findvsget/DatabaseConfigurationBaseIntegrationTest.java new file mode 100644 index 0000000000..3ac46c3a39 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/findvsget/DatabaseConfigurationBaseIntegrationTest.java @@ -0,0 +1,43 @@ +package com.baeldung.spring.data.persistence.findvsget; + +import static com.baeldung.spring.data.persistence.findvsget.UserProvider.userSource; +import static org.assertj.core.api.Assumptions.assumeThat; + +import com.baeldung.spring.data.persistence.findvsget.entity.User; +import com.baeldung.spring.data.persistence.findvsget.repository.SimpleUserRepository; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.provider.Arguments; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest(classes = ApplicationConfig.class, properties = { + "spring.jpa.generate-ddl=true", + "spring.jpa.show-sql=false" +}) +abstract class DatabaseConfigurationBaseIntegrationTest { + + private static final int NUMBER_OF_USERS = 10; + + @Autowired + private SimpleUserRepository repository; + + @BeforeEach + void populateDatabase() { + final List users = userSource() + .map(Arguments::get) + .map(s -> new User(((Long) s[0]), s[1].toString(), s[2].toString())) + .collect(Collectors.toList()); + repository.saveAll(users); + assumeThat(repository.findAll()).hasSize(NUMBER_OF_USERS); + } + + @AfterEach + void clearDatabase() { + repository.deleteAll(); + } + +} + diff --git a/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/findvsget/FindUserIntegrationIntegrationTest.java b/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/findvsget/FindUserIntegrationIntegrationTest.java new file mode 100644 index 0000000000..efe370b38a --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/findvsget/FindUserIntegrationIntegrationTest.java @@ -0,0 +1,37 @@ +package com.baeldung.spring.data.persistence.findvsget; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.baeldung.spring.data.persistence.findvsget.entity.User; +import com.baeldung.spring.data.persistence.findvsget.service.SimpleUserService; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.beans.factory.annotation.Autowired; + +@DisplayName("findBy test:") +class FindUserIntegrationIntegrationTest extends DatabaseConfigurationBaseIntegrationTest { + + + @Autowired + private SimpleUserService service; + + @ParameterizedTest + @ArgumentsSource(UserProvider.class) + @DisplayName("when looking for a user by an existing ID returns a user") + void whenGettingUserByCorrectIdThenReturnUser(Long id, String firstName, String lastName) { + final User expected = new User(id, firstName, lastName); + final User actual = service.findUser(id); + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @DisplayName("when looking for a user by a non-existing ID returns null") + @ValueSource(longs = {11, 12, 13}) + void whenGettingUserByIncorrectIdThenReturnNull(Long id) { + assertThat(service.findUser(id)).isNull(); + } + + +} diff --git a/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/findvsget/GetReferenceIntegrationIntegrationTest.java b/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/findvsget/GetReferenceIntegrationIntegrationTest.java new file mode 100644 index 0000000000..c4be5d1ccd --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/findvsget/GetReferenceIntegrationIntegrationTest.java @@ -0,0 +1,125 @@ +package com.baeldung.spring.data.persistence.findvsget; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import com.baeldung.spring.data.persistence.findvsget.entity.User; +import com.baeldung.spring.data.persistence.findvsget.repository.NewTransactionUserRepository; +import com.baeldung.spring.data.persistence.findvsget.repository.SimpleUserRepository; +import com.baeldung.spring.data.persistence.findvsget.service.NonTransactionalUserReferenceService; +import com.baeldung.spring.data.persistence.findvsget.service.TransactionalUserReferenceService; +import org.hibernate.LazyInitializationException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; +import org.springframework.beans.factory.annotation.Autowired; + + +@DisplayName("getReferenceBy test:") +class GetReferenceIntegrationIntegrationTest extends DatabaseConfigurationBaseIntegrationTest { + + private static final long EXISTING_ID = 1L; + + @Nested + @DisplayName("given non-transactional service, even if user exists") + class GivenNonTransactionalService { + + @Autowired + private NonTransactionalUserReferenceService nonTransactionalService; + + @BeforeEach + void configureService(@Autowired SimpleUserRepository repository) { + nonTransactionalService.setRepository(repository); + } + + @Test + void whenFindUserReferenceUsingOutsideServiceThenThrowsException() { + final User user = nonTransactionalService.findUserReference(EXISTING_ID); + assertThatExceptionOfType(LazyInitializationException.class) + .isThrownBy(user::getFirstName); + } + + @Test + void whenFindUserReferenceNotUsingOutsideServiceThenDontThrowException() { + final User user = nonTransactionalService.findUserReference(EXISTING_ID); + assertThat(user).isNotNull(); + } + + @Test + void whenFindUserReferenceUsingInsideServiceThenThrowsException() { + assertThatExceptionOfType(LazyInitializationException.class) + .isThrownBy(() -> nonTransactionalService.findAndUseUserReference(EXISTING_ID)); + } + } + + @Nested + @DisplayName("given transactional service with simple repository, even if user exists") + class GivenTransactionalService { + + @Autowired + private TransactionalUserReferenceService transactionalService; + + @BeforeEach + void configureService(@Autowired SimpleUserRepository repository) { + transactionalService.setRepository(repository); + } + + @Test + void whenFindUserReferenceUsingOutsideServiceThenThrowsException() { + final User user = transactionalService.findUserReference(EXISTING_ID); + assertThatExceptionOfType(LazyInitializationException.class) + .isThrownBy(user::getFirstName); + } + + @Test + void whenFindUserReferenceNotUsingOutsideServiceThenDontThrowException() { + final User user = transactionalService.findUserReference(EXISTING_ID); + assertThat(user).isNotNull(); + } + + @ParameterizedTest + @ArgumentsSource(UserProvider.class) + void whenFindUserReferenceUsingInsideServiceThenReturnsUser(Long id, String firstName, String lastName) { + final User expected = new User(id, firstName, lastName); + final User actual = transactionalService.findAndUseUserReference(id); + assertThat(actual).isEqualTo(expected); + } + } + + @Nested + @DisplayName("given transactional service with new transaction repository, even if user exists") + class GivenTransactionalServiceWithNewTransactionRepository { + + @Autowired + private TransactionalUserReferenceService transactionalServiceWithNewTransactionRepository; + + @BeforeEach + void configureService(@Autowired NewTransactionUserRepository repository) { + transactionalServiceWithNewTransactionRepository.setRepository(repository); + } + + @Test + void whenFindUserReferenceUsingOutsideServiceThenThrowsException() { + final User user = transactionalServiceWithNewTransactionRepository + .findUserReference(EXISTING_ID); + assertThatExceptionOfType(LazyInitializationException.class) + .isThrownBy(user::getFirstName); + } + + @Test + void whenFindUserReferenceNotUsingOutsideServiceThenDontThrowException() { + final User user = transactionalServiceWithNewTransactionRepository.findUserReference(EXISTING_ID); + assertThat(user).isNotNull(); + } + + @Test + void whenFindUserReferenceUsingInsideServiceThenThrowsExceptionDueToSeparateTransactions() { + assertThatExceptionOfType(LazyInitializationException.class) + .isThrownBy(() -> transactionalServiceWithNewTransactionRepository + .findAndUseUserReference(EXISTING_ID)); + } + } +} diff --git a/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/findvsget/UserProvider.java b/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/findvsget/UserProvider.java new file mode 100644 index 0000000000..f0222dae50 --- /dev/null +++ b/persistence-modules/spring-data-jpa-repo-4/src/test/java/com/baeldung/spring/data/persistence/findvsget/UserProvider.java @@ -0,0 +1,30 @@ +package com.baeldung.spring.data.persistence.findvsget; + + +import java.util.stream.Stream; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; + +public class UserProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(final ExtensionContext context) { + return userSource(); + } + + static Stream userSource() { + return Stream.of( + Arguments.of(1L, "Saundra", "Krystek"), + Arguments.of(2L, "Korey", "Venners"), + Arguments.of(3L, "Lory", "Daffey"), + Arguments.of(4L, "Michail", "Spinella"), + Arguments.of(5L, "Emanuel", "Geertje"), + Arguments.of(6L, "Jervis", "Waugh"), + Arguments.of(7L, "Chantal", "Soldan"), + Arguments.of(8L, "Darnall", "Fanner"), + Arguments.of(9L, "Cordelia", "Hindge"), + Arguments.of(10L, "Lem", "Pitcock") + ); + } +} diff --git a/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/converter/CaseInsensitiveWeekDayConverter.java b/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/converter/CaseInsensitiveWeekDayConverter.java new file mode 100644 index 0000000000..8b06fedc78 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/converter/CaseInsensitiveWeekDayConverter.java @@ -0,0 +1,16 @@ +package com.baeldung.caseinsensitiveenum.converter; + +import com.baeldung.caseinsensitiveenum.week.WeekDays; +import org.springframework.core.convert.converter.Converter; + +public class CaseInsensitiveWeekDayConverter implements Converter { + + @Override + public WeekDays convert(final String source) { + try { + return WeekDays.valueOf(source.trim()); + } catch (IllegalArgumentException exception) { + return WeekDays.valueOf(source.trim().toUpperCase()); + } + } +} diff --git a/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/converter/StrictNullableWeekDayConverter.java b/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/converter/StrictNullableWeekDayConverter.java new file mode 100644 index 0000000000..dd9f7fb92a --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/converter/StrictNullableWeekDayConverter.java @@ -0,0 +1,15 @@ +package com.baeldung.caseinsensitiveenum.converter; + +import com.baeldung.caseinsensitiveenum.week.WeekDays; +import org.springframework.core.convert.converter.Converter; + +public class StrictNullableWeekDayConverter implements Converter { + @Override + public WeekDays convert(final String source) { + try { + return WeekDays.valueOf(source.trim()); + } catch (IllegalArgumentException e) { + return null; + } + } +} diff --git a/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/nonconventionalweek/NonConventionalWeekDays.java b/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/nonconventionalweek/NonConventionalWeekDays.java new file mode 100644 index 0000000000..72e1589de7 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/nonconventionalweek/NonConventionalWeekDays.java @@ -0,0 +1,5 @@ +package com.baeldung.caseinsensitiveenum.nonconventionalweek; + +public enum NonConventionalWeekDays { + Mon$Day, Tues$DAY_, Wednes$day, THURS$day_, Fri$Day$_$, Satur$DAY_, Sun$Day +} diff --git a/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/nonconventionalweek/NonConventionalWeekDaysHolder.java b/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/nonconventionalweek/NonConventionalWeekDaysHolder.java new file mode 100644 index 0000000000..9cd2cf4369 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/nonconventionalweek/NonConventionalWeekDaysHolder.java @@ -0,0 +1,85 @@ +package com.baeldung.caseinsensitiveenum.nonconventionalweek; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class NonConventionalWeekDaysHolder { + + @Value("${monday}") + private NonConventionalWeekDays monday; + + @Value("${tuesday}") + private NonConventionalWeekDays tuesday; + + @Value("${wednesday}") + private NonConventionalWeekDays wednesday; + + @Value("${thursday}") + private NonConventionalWeekDays thursday; + + @Value("${friday}") + private NonConventionalWeekDays friday; + + @Value("${saturday}") + private NonConventionalWeekDays saturday; + + @Value("${sunday}") + private NonConventionalWeekDays sunday; + + public NonConventionalWeekDays getMonday() { + return monday; + } + + public void setMonday(final NonConventionalWeekDays monday) { + this.monday = monday; + } + + public NonConventionalWeekDays getTuesday() { + return tuesday; + } + + public void setTuesday(final NonConventionalWeekDays tuesday) { + this.tuesday = tuesday; + } + + public NonConventionalWeekDays getWednesday() { + return wednesday; + } + + public void setWednesday(final NonConventionalWeekDays wednesday) { + this.wednesday = wednesday; + } + + public NonConventionalWeekDays getThursday() { + return thursday; + } + + public void setThursday(final NonConventionalWeekDays thursday) { + this.thursday = thursday; + } + + public NonConventionalWeekDays getFriday() { + return friday; + } + + public void setFriday(final NonConventionalWeekDays friday) { + this.friday = friday; + } + + public NonConventionalWeekDays getSaturday() { + return saturday; + } + + public void setSaturday(final NonConventionalWeekDays saturday) { + this.saturday = saturday; + } + + public NonConventionalWeekDays getSunday() { + return sunday; + } + + public void setSunday(final NonConventionalWeekDays sunday) { + this.sunday = sunday; + } +} diff --git a/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/week/SpELWeekDaysHolder.java b/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/week/SpELWeekDaysHolder.java new file mode 100644 index 0000000000..6c56c0a9fe --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/week/SpELWeekDaysHolder.java @@ -0,0 +1,85 @@ +package com.baeldung.caseinsensitiveenum.week; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class SpELWeekDaysHolder { + + @Value("#{'${monday}'.toUpperCase()}") + private WeekDays monday; + + @Value("#{'${tuesday}'.toUpperCase()}") + private WeekDays tuesday; + + @Value("#{'${wednesday}'.toUpperCase()}") + private WeekDays wednesday; + + @Value("#{'${thursday}'.toUpperCase()}") + private WeekDays thursday; + + @Value("#{'${friday}'.toUpperCase()}") + private WeekDays friday; + + @Value("#{'${saturday}'.toUpperCase()}") + private WeekDays saturday; + + @Value("#{'${sunday}'.toUpperCase()}") + private WeekDays sunday; + + public WeekDays getMonday() { + return monday; + } + + public void setMonday(final WeekDays monday) { + this.monday = monday; + } + + public WeekDays getTuesday() { + return tuesday; + } + + public void setTuesday(final WeekDays tuesday) { + this.tuesday = tuesday; + } + + public WeekDays getWednesday() { + return wednesday; + } + + public void setWednesday(final WeekDays wednesday) { + this.wednesday = wednesday; + } + + public WeekDays getThursday() { + return thursday; + } + + public void setThursday(final WeekDays thursday) { + this.thursday = thursday; + } + + public WeekDays getFriday() { + return friday; + } + + public void setFriday(final WeekDays friday) { + this.friday = friday; + } + + public WeekDays getSaturday() { + return saturday; + } + + public void setSaturday(final WeekDays saturday) { + this.saturday = saturday; + } + + public WeekDays getSunday() { + return sunday; + } + + public void setSunday(final WeekDays sunday) { + this.sunday = sunday; + } +} diff --git a/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/week/WeekDays.java b/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/week/WeekDays.java new file mode 100644 index 0000000000..21e7b6662a --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/week/WeekDays.java @@ -0,0 +1,5 @@ +package com.baeldung.caseinsensitiveenum.week; + +public enum WeekDays { + MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY +} diff --git a/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/week/WeekDaysHolder.java b/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/week/WeekDaysHolder.java new file mode 100644 index 0000000000..299a61a3fd --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-4/src/main/java/com/baeldung/caseinsensitiveenum/week/WeekDaysHolder.java @@ -0,0 +1,85 @@ +package com.baeldung.caseinsensitiveenum.week; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class WeekDaysHolder { + + @Value("${monday}") + private WeekDays monday; + + @Value("${tuesday}") + private WeekDays tuesday; + + @Value("${wednesday}") + private WeekDays wednesday; + + @Value("${thursday}") + private WeekDays thursday; + + @Value("${friday}") + private WeekDays friday; + + @Value("${saturday}") + private WeekDays saturday; + + @Value("${sunday}") + private WeekDays sunday; + + public WeekDays getMonday() { + return monday; + } + + public void setMonday(final WeekDays monday) { + this.monday = monday; + } + + public WeekDays getTuesday() { + return tuesday; + } + + public void setTuesday(final WeekDays tuesday) { + this.tuesday = tuesday; + } + + public WeekDays getWednesday() { + return wednesday; + } + + public void setWednesday(final WeekDays wednesday) { + this.wednesday = wednesday; + } + + public WeekDays getThursday() { + return thursday; + } + + public void setThursday(final WeekDays thursday) { + this.thursday = thursday; + } + + public WeekDays getFriday() { + return friday; + } + + public void setFriday(final WeekDays friday) { + this.friday = friday; + } + + public WeekDays getSaturday() { + return saturday; + } + + public void setSaturday(final WeekDays saturday) { + this.saturday = saturday; + } + + public WeekDays getSunday() { + return sunday; + } + + public void setSunday(final WeekDays sunday) { + this.sunday = sunday; + } +} diff --git a/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/CaseInsensitiveStringToEnumConverterUnitTest.java b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/CaseInsensitiveStringToEnumConverterUnitTest.java new file mode 100644 index 0000000000..7470b3d9dd --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/CaseInsensitiveStringToEnumConverterUnitTest.java @@ -0,0 +1,49 @@ +package com.baeldung.caseinsensitiveenum; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.baeldung.caseinsensitiveenum.CaseInsensitiveStringToEnumConverterUnitTest.WeekDayConverterConfiguration; +import com.baeldung.caseinsensitiveenum.converter.CaseInsensitiveWeekDayConverter; +import com.baeldung.caseinsensitiveenum.providers.WeekDayHolderArgumentsProvider; +import com.baeldung.caseinsensitiveenum.week.WeekDays; +import com.baeldung.caseinsensitiveenum.week.WeekDaysHolder; +import java.util.function.Function; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.support.DefaultConversionService; + +@SpringBootTest(properties = { + "monday=monday", + "tuesday=tuesday", + "wednesday=wednesday", + "thursday=THURSDAY", + "friday=Friday", + "saturday=saturDAY", + "sunday=sUndAy", +}, classes = {WeekDaysHolder.class, WeekDayConverterConfiguration.class}) +class CaseInsensitiveStringToEnumConverterUnitTest { + + public static class WeekDayConverterConfiguration { + @Bean + public ConversionService conversionService() { + final DefaultConversionService defaultConversionService = new DefaultConversionService(); + defaultConversionService.addConverter(new CaseInsensitiveWeekDayConverter()); + return defaultConversionService; + } + } + + @Autowired + private WeekDaysHolder holder; + + @ParameterizedTest + @ArgumentsSource(WeekDayHolderArgumentsProvider.class) + void givenPropertiesWhenInjectEnumThenValueIsNull( + Function methodReference, WeekDays expected) { + WeekDays actual = methodReference.apply(holder); + assertThat(actual).isEqualTo(expected); + } +} diff --git a/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/LenientStringToEnumConverterUnitTest.java b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/LenientStringToEnumConverterUnitTest.java new file mode 100644 index 0000000000..3f739b10cf --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/LenientStringToEnumConverterUnitTest.java @@ -0,0 +1,35 @@ +package com.baeldung.caseinsensitiveenum; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.baeldung.caseinsensitiveenum.providers.WeekDayHolderArgumentsProvider; +import com.baeldung.caseinsensitiveenum.week.WeekDays; +import com.baeldung.caseinsensitiveenum.week.WeekDaysHolder; +import java.util.function.Function; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest(properties = { + "monday=Mon-Day!", + "tuesday=TuesDAY#", + "wednesday=Wednes@day", + "thursday=THURSday^", + "friday=Fri:Day_%", + "saturday=Satur_DAY*", + "sunday=Sun+Day", +}, classes = WeekDaysHolder.class) +class LenientStringToEnumConverterUnitTest { + + @Autowired + private WeekDaysHolder holder; + + @ParameterizedTest + @ArgumentsSource(WeekDayHolderArgumentsProvider.class) + void givenPropertiesWhenInjectEnumThenValueIsPresent( + Function methodReference, WeekDays expected) { + WeekDays actual = methodReference.apply(holder); + assertThat(actual).isEqualTo(expected); + } +} diff --git a/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/NonConventionalStringToEnumLenientConverterUnitTest.java b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/NonConventionalStringToEnumLenientConverterUnitTest.java new file mode 100644 index 0000000000..21c2e35799 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/NonConventionalStringToEnumLenientConverterUnitTest.java @@ -0,0 +1,35 @@ +package com.baeldung.caseinsensitiveenum; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.baeldung.caseinsensitiveenum.nonconventionalweek.NonConventionalWeekDays; +import com.baeldung.caseinsensitiveenum.nonconventionalweek.NonConventionalWeekDaysHolder; +import com.baeldung.caseinsensitiveenum.providers.NonConventionalWeekDayHolderArgumentsProvider; +import java.util.function.Function; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest(properties = { + "monday=Mon-Day!", + "tuesday=TuesDAY#", + "wednesday=Wednes@day", + "thursday=THURSday^", + "friday=Fri:Day_%", + "saturday=Satur_DAY*", + "sunday=Sun+Day", +}, classes = NonConventionalWeekDaysHolder.class) +class NonConventionalStringToEnumLenientConverterUnitTest { + + @Autowired + private NonConventionalWeekDaysHolder holder; + + @ParameterizedTest + @ArgumentsSource(NonConventionalWeekDayHolderArgumentsProvider.class) + void givenPropertiesWhenInjectEnumThenValueIsPresent( + Function methodReference, NonConventionalWeekDays expected) { + NonConventionalWeekDays actual = methodReference.apply(holder); + assertThat(actual).isEqualTo(expected); + } +} diff --git a/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/SpELCaseInsensitiveStringToEnumConverterUnitTest.java b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/SpELCaseInsensitiveStringToEnumConverterUnitTest.java new file mode 100644 index 0000000000..7d259c6de4 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/SpELCaseInsensitiveStringToEnumConverterUnitTest.java @@ -0,0 +1,49 @@ +package com.baeldung.caseinsensitiveenum; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.baeldung.caseinsensitiveenum.CaseInsensitiveStringToEnumConverterUnitTest.WeekDayConverterConfiguration; +import com.baeldung.caseinsensitiveenum.converter.StrictNullableWeekDayConverter; +import com.baeldung.caseinsensitiveenum.providers.SpELWeekDayHolderArgumentsProvider; +import com.baeldung.caseinsensitiveenum.week.SpELWeekDaysHolder; +import com.baeldung.caseinsensitiveenum.week.WeekDays; +import java.util.function.Function; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.support.DefaultConversionService; + +@SpringBootTest(properties = { + "monday=monday", + "tuesday=tuesday", + "wednesday=wednesday", + "thursday=THURSDAY", + "friday=Friday", + "saturday=saturDAY", + "sunday=sUndAy", +}, classes = {SpELWeekDaysHolder.class, WeekDayConverterConfiguration.class}) +class SpELCaseInsensitiveStringToEnumConverterUnitTest { + + public static class WeekDayConverterConfiguration { + @Bean + public ConversionService conversionService() { + final DefaultConversionService defaultConversionService = new DefaultConversionService(); + defaultConversionService.addConverter(new StrictNullableWeekDayConverter()); + return defaultConversionService; + } + } + + @Autowired + private SpELWeekDaysHolder holder; + + @ParameterizedTest + @ArgumentsSource(SpELWeekDayHolderArgumentsProvider.class) + void givenPropertiesWhenInjectEnumThenValueIsNull( + Function methodReference, WeekDays expected) { + WeekDays actual = methodReference.apply(holder); + assertThat(actual).isEqualTo(expected); + } +} diff --git a/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/StrictStringToEnumConverterNegativeUnitTest.java b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/StrictStringToEnumConverterNegativeUnitTest.java new file mode 100644 index 0000000000..ffa3ee14be --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/StrictStringToEnumConverterNegativeUnitTest.java @@ -0,0 +1,49 @@ +package com.baeldung.caseinsensitiveenum; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.baeldung.caseinsensitiveenum.StrictStringToEnumConverterNegativeUnitTest.WeekDayConverterConfiguration; +import com.baeldung.caseinsensitiveenum.converter.StrictNullableWeekDayConverter; +import com.baeldung.caseinsensitiveenum.providers.WeekDayHolderArgumentsProvider; +import com.baeldung.caseinsensitiveenum.week.WeekDays; +import com.baeldung.caseinsensitiveenum.week.WeekDaysHolder; +import java.util.function.Function; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.support.DefaultConversionService; + +@SpringBootTest(properties = { + "monday=monday", + "tuesday=tuesday", + "wednesday=wednesday", + "thursday=thursday", + "friday=friday", + "saturday=saturday", + "sunday=sunday", +}, classes = {WeekDaysHolder.class, WeekDayConverterConfiguration.class}) +class StrictStringToEnumConverterNegativeUnitTest { + + public static class WeekDayConverterConfiguration { + @Bean + public ConversionService conversionService() { + final DefaultConversionService defaultConversionService = new DefaultConversionService(); + defaultConversionService.addConverter(new StrictNullableWeekDayConverter()); + return defaultConversionService; + } + } + + @Autowired + private WeekDaysHolder holder; + + @ParameterizedTest + @ArgumentsSource(WeekDayHolderArgumentsProvider.class) + void givenPropertiesWhenInjectEnumThenValueIsNull( + Function methodReference, WeekDays ignored) { + WeekDays actual = methodReference.apply(holder); + assertThat(actual).isNull(); + } +} diff --git a/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/StrictStringToEnumConverterPositiveUnitTest.java b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/StrictStringToEnumConverterPositiveUnitTest.java new file mode 100644 index 0000000000..2d057a4f4d --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/StrictStringToEnumConverterPositiveUnitTest.java @@ -0,0 +1,49 @@ +package com.baeldung.caseinsensitiveenum; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.baeldung.caseinsensitiveenum.StrictStringToEnumConverterNegativeUnitTest.WeekDayConverterConfiguration; +import com.baeldung.caseinsensitiveenum.converter.StrictNullableWeekDayConverter; +import com.baeldung.caseinsensitiveenum.providers.WeekDayHolderArgumentsProvider; +import com.baeldung.caseinsensitiveenum.week.WeekDays; +import com.baeldung.caseinsensitiveenum.week.WeekDaysHolder; +import java.util.function.Function; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.support.DefaultConversionService; + +@SpringBootTest(properties = { + "monday=MONDAY", + "tuesday=TUESDAY", + "wednesday=WEDNESDAY", + "thursday=THURSDAY", + "friday=FRIDAY", + "saturday=SATURDAY", + "sunday=SUNDAY", +}, classes = {WeekDaysHolder.class, WeekDayConverterConfiguration.class}) +class StrictStringToEnumConverterPositiveUnitTest { + + public static class WeekDayConverterConfiguration { + @Bean + public ConversionService conversionService() { + final DefaultConversionService defaultConversionService = new DefaultConversionService(); + defaultConversionService.addConverter(new StrictNullableWeekDayConverter()); + return defaultConversionService; + } + } + + @Autowired + private WeekDaysHolder holder; + + @ParameterizedTest + @ArgumentsSource(WeekDayHolderArgumentsProvider.class) + void givenPropertiesWhenInjectEnumThenValueIsNull( + Function methodReference, WeekDays expected) { + WeekDays actual = methodReference.apply(holder); + assertThat(actual).isEqualTo(expected); + } +} diff --git a/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/providers/NonConventionalWeekDayHolderArgumentsProvider.java b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/providers/NonConventionalWeekDayHolderArgumentsProvider.java new file mode 100644 index 0000000000..b4ed8f8388 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/providers/NonConventionalWeekDayHolderArgumentsProvider.java @@ -0,0 +1,35 @@ +package com.baeldung.caseinsensitiveenum.providers; + + + +import static com.baeldung.caseinsensitiveenum.nonconventionalweek.NonConventionalWeekDays.Fri$Day$_$; +import static com.baeldung.caseinsensitiveenum.nonconventionalweek.NonConventionalWeekDays.Mon$Day; +import static com.baeldung.caseinsensitiveenum.nonconventionalweek.NonConventionalWeekDays.Satur$DAY_; +import static com.baeldung.caseinsensitiveenum.nonconventionalweek.NonConventionalWeekDays.Sun$Day; +import static com.baeldung.caseinsensitiveenum.nonconventionalweek.NonConventionalWeekDays.THURS$day_; +import static com.baeldung.caseinsensitiveenum.nonconventionalweek.NonConventionalWeekDays.Tues$DAY_; +import static com.baeldung.caseinsensitiveenum.nonconventionalweek.NonConventionalWeekDays.Wednes$day; + +import com.baeldung.caseinsensitiveenum.nonconventionalweek.NonConventionalWeekDays; +import com.baeldung.caseinsensitiveenum.nonconventionalweek.NonConventionalWeekDaysHolder; +import java.util.function.Function; +import java.util.stream.Stream; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; + +public class NonConventionalWeekDayHolderArgumentsProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(final ExtensionContext extensionContext) { + return Stream.of( + Arguments.of(((Function) NonConventionalWeekDaysHolder::getMonday),Mon$Day), + Arguments.of(((Function) NonConventionalWeekDaysHolder::getTuesday),Tues$DAY_), + Arguments.of(((Function) NonConventionalWeekDaysHolder::getWednesday),Wednes$day), + Arguments.of(((Function) NonConventionalWeekDaysHolder::getThursday),THURS$day_), + Arguments.of(((Function) NonConventionalWeekDaysHolder::getFriday),Fri$Day$_$), + Arguments.of(((Function) NonConventionalWeekDaysHolder::getSaturday),Satur$DAY_), + Arguments.of(((Function) NonConventionalWeekDaysHolder::getSunday),Sun$Day) + ); + } +} diff --git a/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/providers/SpELWeekDayHolderArgumentsProvider.java b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/providers/SpELWeekDayHolderArgumentsProvider.java new file mode 100644 index 0000000000..d6e91be0a1 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/providers/SpELWeekDayHolderArgumentsProvider.java @@ -0,0 +1,34 @@ +package com.baeldung.caseinsensitiveenum.providers; + + +import static com.baeldung.caseinsensitiveenum.week.WeekDays.FRIDAY; +import static com.baeldung.caseinsensitiveenum.week.WeekDays.MONDAY; +import static com.baeldung.caseinsensitiveenum.week.WeekDays.SATURDAY; +import static com.baeldung.caseinsensitiveenum.week.WeekDays.SUNDAY; +import static com.baeldung.caseinsensitiveenum.week.WeekDays.THURSDAY; +import static com.baeldung.caseinsensitiveenum.week.WeekDays.TUESDAY; +import static com.baeldung.caseinsensitiveenum.week.WeekDays.WEDNESDAY; + +import com.baeldung.caseinsensitiveenum.week.WeekDays; +import com.baeldung.caseinsensitiveenum.week.SpELWeekDaysHolder; +import java.util.function.Function; +import java.util.stream.Stream; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; + +public class SpELWeekDayHolderArgumentsProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(final ExtensionContext extensionContext) { + return Stream.of( + Arguments.of(((Function) SpELWeekDaysHolder::getMonday), MONDAY), + Arguments.of(((Function) SpELWeekDaysHolder::getTuesday), TUESDAY), + Arguments.of(((Function) SpELWeekDaysHolder::getWednesday), WEDNESDAY), + Arguments.of(((Function) SpELWeekDaysHolder::getThursday), THURSDAY), + Arguments.of(((Function) SpELWeekDaysHolder::getFriday), FRIDAY), + Arguments.of(((Function) SpELWeekDaysHolder::getSaturday), SATURDAY), + Arguments.of(((Function) SpELWeekDaysHolder::getSunday), SUNDAY) + ); + } +} diff --git a/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/providers/WeekDayHolderArgumentsProvider.java b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/providers/WeekDayHolderArgumentsProvider.java new file mode 100644 index 0000000000..6c0ebd2a20 --- /dev/null +++ b/spring-boot-modules/spring-boot-properties-4/src/test/java/com/baeldung/caseinsensitiveenum/providers/WeekDayHolderArgumentsProvider.java @@ -0,0 +1,34 @@ +package com.baeldung.caseinsensitiveenum.providers; + + +import static com.baeldung.caseinsensitiveenum.week.WeekDays.FRIDAY; +import static com.baeldung.caseinsensitiveenum.week.WeekDays.MONDAY; +import static com.baeldung.caseinsensitiveenum.week.WeekDays.SATURDAY; +import static com.baeldung.caseinsensitiveenum.week.WeekDays.SUNDAY; +import static com.baeldung.caseinsensitiveenum.week.WeekDays.THURSDAY; +import static com.baeldung.caseinsensitiveenum.week.WeekDays.TUESDAY; +import static com.baeldung.caseinsensitiveenum.week.WeekDays.WEDNESDAY; + +import com.baeldung.caseinsensitiveenum.week.WeekDays; +import com.baeldung.caseinsensitiveenum.week.WeekDaysHolder; +import java.util.function.Function; +import java.util.stream.Stream; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; + +public class WeekDayHolderArgumentsProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(final ExtensionContext extensionContext) { + return Stream.of( + Arguments.of(((Function) WeekDaysHolder::getMonday), MONDAY), + Arguments.of(((Function) WeekDaysHolder::getTuesday), TUESDAY), + Arguments.of(((Function) WeekDaysHolder::getWednesday), WEDNESDAY), + Arguments.of(((Function) WeekDaysHolder::getThursday), THURSDAY), + Arguments.of(((Function) WeekDaysHolder::getFriday), FRIDAY), + Arguments.of(((Function) WeekDaysHolder::getSaturday), SATURDAY), + Arguments.of(((Function) WeekDaysHolder::getSunday), SUNDAY) + ); + } +} diff --git a/spring-reactive-modules/spring-reactive-performance/README.md b/spring-reactive-modules/spring-reactive-performance/README.md index 16aac3d419..ea62ebab56 100644 --- a/spring-reactive-modules/spring-reactive-performance/README.md +++ b/spring-reactive-modules/spring-reactive-performance/README.md @@ -1,3 +1,6 @@ ## Spring Reactive Performance This module contains articles about reactive Spring Boot. + +## Relevant Articles +- [Reactor WebFlux vs Virtual Threads](https://www.baeldung.com/java-reactor-webflux-vs-virtual-threads) diff --git a/spring-security-modules/spring-security-web-boot-1/pom.xml b/spring-security-modules/spring-security-web-boot-1/pom.xml index e93b0b4f03..af9a02b7b2 100644 --- a/spring-security-modules/spring-security-web-boot-1/pom.xml +++ b/spring-security-modules/spring-security-web-boot-1/pom.xml @@ -11,8 +11,9 @@ com.baeldung - spring-security-modules + parent-boot-3 0.0.1-SNAPSHOT + ../../parent-boot-3 @@ -34,7 +35,7 @@ org.thymeleaf.extras - thymeleaf-extras-springsecurity5 + thymeleaf-extras-springsecurity6 org.springframework.boot @@ -81,11 +82,6 @@ org.springframework.security spring-security-core - - javax.servlet.jsp.jstl - jstl-api - ${jstl.version} - org.springframework.security spring-security-config @@ -100,6 +96,11 @@ ${ehcache-core.version} jar + + io.rest-assured + rest-assured + test + diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/AppConfig.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/AppConfig.java index ab2cc71fec..8023ef7c78 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/AppConfig.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/AppConfig.java @@ -15,14 +15,14 @@ import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @SpringBootApplication @PropertySource({"classpath:persistence-h2.properties", "classpath:application-defaults.properties"}) @EnableJpaRepositories(basePackages = {"com.baeldung.relationships.repositories"}) @EnableWebMvc @Import(SpringSecurityConfig.class) -public class AppConfig extends WebMvcConfigurerAdapter { +public class AppConfig implements WebMvcConfigurer { @Autowired private Environment env; @@ -41,7 +41,7 @@ public class AppConfig extends WebMvcConfigurerAdapter { public LocalContainerEntityManagerFactoryBean entityManagerFactory() { final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource()); - em.setPackagesToScan(new String[] { "com.baeldung.relationships.models" }); + em.setPackagesToScan("com.baeldung.relationships.models"); em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); em.setJpaProperties(additionalProperties()); return em; diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/SpringSecurityConfig.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/SpringSecurityConfig.java index bce0e21e7a..9b0e8f32b9 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/SpringSecurityConfig.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/SpringSecurityConfig.java @@ -1,6 +1,6 @@ package com.baeldung.relationships; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; @@ -13,6 +13,7 @@ import org.springframework.security.config.annotation.authentication.builders.Au 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.WebSecurityCustomizer; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension; @@ -47,12 +48,10 @@ public class SpringSecurityConfig { @Bean public UserDetailsManager users(HttpSecurity http) throws Exception { - AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManagerBuilder.class) - .userDetailsService(userDetailsService) - .passwordEncoder(encoder()) - .and() - .authenticationProvider(authenticationProvider()) - .build(); + AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class); + authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(encoder()); + authenticationManagerBuilder.authenticationProvider(authenticationProvider()); + AuthenticationManager authenticationManager = authenticationManagerBuilder.build(); JdbcUserDetailsManager jdbcUserDetailsManager = new JdbcUserDetailsManager(dataSource); jdbcUserDetailsManager.setAuthenticationManager(authenticationManager); @@ -61,22 +60,16 @@ public class SpringSecurityConfig { @Bean public WebSecurityCustomizer webSecurityCustomizer() { - return (web) -> web.ignoring() - .antMatchers("/resources/**"); + return web -> web.ignoring().requestMatchers("/resources/**"); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.authorizeRequests() - .antMatchers("/login") - .permitAll() - .and() - .formLogin() - .permitAll() - .successHandler(successHandler) - .and() - .csrf() - .disable(); + http.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> + authorizationManagerRequestMatcherRegistry.requestMatchers("/login").permitAll()) + .formLogin(httpSecurityFormLoginConfigurer -> + httpSecurityFormLoginConfigurer.permitAll().successHandler(successHandler)) + .csrf(AbstractHttpConfigurer::disable); return http.build(); } diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/models/AppUser.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/models/AppUser.java index 34bf775c1c..56e0fac833 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/models/AppUser.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/models/AppUser.java @@ -2,12 +2,12 @@ package com.baeldung.relationships.models; import java.util.Date; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; @Entity @Table(name = "users") diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/models/Tweet.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/models/Tweet.java index 2f593d5784..6c8921a941 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/models/Tweet.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/models/Tweet.java @@ -3,14 +3,14 @@ package com.baeldung.relationships.models; import java.util.HashSet; import java.util.Set; -import javax.persistence.CollectionTable; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; +import jakarta.persistence.CollectionTable; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; @Entity @Table(name = "Tweet") diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/repositories/TweetRepository.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/repositories/TweetRepository.java index 685a1a8ab9..ebefe104b1 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/repositories/TweetRepository.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/repositories/TweetRepository.java @@ -3,11 +3,12 @@ package com.baeldung.relationships.repositories; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.PagingAndSortingRepository; import com.baeldung.relationships.models.Tweet; -public interface TweetRepository extends PagingAndSortingRepository { +public interface TweetRepository extends PagingAndSortingRepository, CrudRepository { @Query("SELECT twt FROM Tweet twt JOIN twt.likes AS lk WHERE lk = ?#{ principal?.username } OR twt.owner = ?#{ principal?.username }") Page getMyTweetsAndTheOnesILiked(Pageable pageable); diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/security/AuthenticationSuccessHandlerImpl.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/security/AuthenticationSuccessHandlerImpl.java index 3636a20c2d..f1375d4fd1 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/security/AuthenticationSuccessHandlerImpl.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/security/AuthenticationSuccessHandlerImpl.java @@ -2,8 +2,8 @@ package com.baeldung.relationships.security; import java.util.Date; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/security/CustomUserDetailsService.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/security/CustomUserDetailsService.java index f8a0f00d90..6f46386939 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/security/CustomUserDetailsService.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/relationships/security/CustomUserDetailsService.java @@ -1,6 +1,6 @@ package com.baeldung.relationships.security; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/config/SecurityConfig.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/config/SecurityConfig.java index ea882f7ba9..60fe5eebf4 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/config/SecurityConfig.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/config/SecurityConfig.java @@ -2,8 +2,11 @@ package com.baeldung.roles.custom.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; 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.configurers.AbstractAuthenticationFilterConfigurer; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; @@ -14,14 +17,9 @@ public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.csrf() - .disable() - .authorizeRequests() - .anyRequest() - .authenticated() - .and() - .formLogin() - .permitAll(); + http.csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> authorizationManagerRequestMatcherRegistry.anyRequest().authenticated()) + .formLogin(AbstractAuthenticationFilterConfigurer::permitAll); return http.build(); } diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/SetupData.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/SetupData.java index 25bf51507a..b8836eb55a 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/SetupData.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/SetupData.java @@ -3,7 +3,7 @@ package com.baeldung.roles.custom.persistence; import java.util.Arrays; import java.util.HashSet; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import com.baeldung.roles.custom.persistence.dao.OrganizationRepository; import com.baeldung.roles.custom.persistence.dao.PrivilegeRepository; diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/model/Foo.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/model/Foo.java index eab7696b47..5bf4c7b76d 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/model/Foo.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/model/Foo.java @@ -1,10 +1,10 @@ package com.baeldung.roles.custom.persistence.model; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; @Entity public class Foo { diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/model/Organization.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/model/Organization.java index f9dc992b8c..532deab4dd 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/model/Organization.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/model/Organization.java @@ -1,10 +1,10 @@ package com.baeldung.roles.custom.persistence.model; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; @Entity public class Organization { diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/model/Privilege.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/model/Privilege.java index 7757ec1bf6..259cae24a3 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/model/Privilege.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/model/Privilege.java @@ -1,10 +1,10 @@ package com.baeldung.roles.custom.persistence.model; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; @Entity public class Privilege { diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/model/User.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/model/User.java index 45ae8c64ca..9a6198bf2d 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/model/User.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/custom/persistence/model/User.java @@ -2,17 +2,17 @@ package com.baeldung.roles.custom.persistence.model; import java.util.Set; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.Table; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; @Entity @Table(name = "user_table") @@ -28,7 +28,9 @@ public class User { private String password; @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "users_privileges", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "privilege_id", referencedColumnName = "id")) + @JoinTable(name = "users_privileges", joinColumns = + @JoinColumn(name = "user_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "privilege_id", referencedColumnName = "id")) private Set privileges; @ManyToOne(fetch = FetchType.EAGER) diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/ip/config/SecurityConfig.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/ip/config/SecurityConfig.java index 6b6fa8c6a3..696dd9c1e5 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/ip/config/SecurityConfig.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/ip/config/SecurityConfig.java @@ -6,10 +6,13 @@ import org.springframework.context.annotation.Configuration; 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.configurers.AbstractAuthenticationFilterConfigurer; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager; @Configuration @EnableWebSecurity @@ -32,19 +35,12 @@ public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.authorizeRequests() - .antMatchers("/login") - .permitAll() - .antMatchers("/foos/**") - .access("isAuthenticated() and hasIpAddress('11.11.11.11')") - .anyRequest() - .authenticated() - .and() - .formLogin() - .permitAll() - .and() - .csrf() - .disable(); + http.authorizeHttpRequests( + authorizationManagerRequestMatcherRegistry -> authorizationManagerRequestMatcherRegistry.requestMatchers("/login").permitAll() + .requestMatchers("/foos/**") + .access(new WebExpressionAuthorizationManager("isAuthenticated() and hasIpAddress('11.11.11.11')")).anyRequest().authenticated()) + .formLogin(AbstractAuthenticationFilterConfigurer::permitAll) + .csrf(AbstractHttpConfigurer::disable); return http.build(); } } \ No newline at end of file diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/ip/web/MainController.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/ip/web/MainController.java index 6fa165433a..c010d1fa3d 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/ip/web/MainController.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/ip/web/MainController.java @@ -2,8 +2,8 @@ package com.baeldung.roles.ip.web; import java.util.List; -import javax.servlet.Filter; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.Filter; +import jakarta.servlet.http.HttpServletRequest; import com.baeldung.roles.custom.persistence.model.Foo; import org.springframework.beans.factory.annotation.Autowired; diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/MyLogoutSuccessHandler.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/MyLogoutSuccessHandler.java index 0ee4707d1b..7d1dd47397 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/MyLogoutSuccessHandler.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/MyLogoutSuccessHandler.java @@ -2,9 +2,9 @@ package com.baeldung.roles.rolesauthorities; import java.io.IOException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/config/SecurityConfig.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/config/SecurityConfig.java index d464b82d1c..682f1faad8 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/config/SecurityConfig.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/config/SecurityConfig.java @@ -10,6 +10,7 @@ import org.springframework.security.config.annotation.authentication.builders.Au 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.WebSecurityCustomizer; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @@ -42,33 +43,22 @@ public class SecurityConfig { @Bean public WebSecurityCustomizer webSecurityCustomizer() { - return (web) -> web.ignoring() - .antMatchers("/resources/**"); + return (web) -> web.ignoring().requestMatchers("/resources/**"); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.csrf() - .disable() - .authorizeRequests() - .antMatchers("/login*", "/logout*", "/protectedbynothing*", "/home*") - .permitAll() - .antMatchers("/protectedbyrole") - .hasRole("USER") - .antMatchers("/protectedbyauthority") - .hasAuthority("READ_PRIVILEGE") - .and() - .formLogin() - .loginPage("/login") - .failureUrl("/login?error=true") - .permitAll() - .and() - .logout() - .logoutSuccessHandler(myLogoutSuccessHandler) - .invalidateHttpSession(false) - .logoutSuccessUrl("/logout.html?logSucc=true") - .deleteCookies("JSESSIONID") - .permitAll(); + http.csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests( + authorizationManagerRequestMatcherRegistry -> + authorizationManagerRequestMatcherRegistry.requestMatchers("/login*", "/logout*", "/protectedbynothing*", "/home*").permitAll() + .requestMatchers("/protectedbyrole").hasRole("USER") + .requestMatchers("/protectedbyauthority").hasAuthority("READ_PRIVILEGE")) + .formLogin(httpSecurityFormLoginConfigurer -> + httpSecurityFormLoginConfigurer.loginPage("/login").failureUrl("/login?error=true").permitAll()) + .logout(httpSecurityLogoutConfigurer -> + httpSecurityLogoutConfigurer.logoutSuccessHandler(myLogoutSuccessHandler).invalidateHttpSession(false) + .logoutSuccessUrl("/logout.html?logSucc=true").deleteCookies("JSESSIONID").permitAll()); return http.build(); } diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/model/Privilege.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/model/Privilege.java index 1e444faf2d..2b07d63031 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/model/Privilege.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/model/Privilege.java @@ -2,11 +2,11 @@ package com.baeldung.roles.rolesauthorities.model; import java.util.Collection; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.ManyToMany; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToMany; @Entity public class Privilege { diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/model/Role.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/model/Role.java index 031c9f0828..fa581b5fa0 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/model/Role.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/model/Role.java @@ -2,13 +2,13 @@ package com.baeldung.roles.rolesauthorities.model; import java.util.Collection; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; @Entity public class Role { diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/model/User.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/model/User.java index cb90947ed6..6c31ac5f03 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/model/User.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/model/User.java @@ -2,17 +2,16 @@ package com.baeldung.roles.rolesauthorities.model; import java.util.Collection; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.Table; - +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.Table; @Entity @Table(name = "user_account") diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/persistence/UserService.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/persistence/UserService.java index 17770e5cd0..89f183e60f 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/persistence/UserService.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/rolesauthorities/persistence/UserService.java @@ -1,6 +1,6 @@ package com.baeldung.roles.rolesauthorities.persistence; -import javax.transaction.Transactional; +import jakarta.transaction.Transactional; import com.baeldung.roles.rolesauthorities.model.User; import org.springframework.beans.factory.annotation.Autowired; diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/voter/MinuteBasedVoter.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/voter/MinuteBasedVoter.java index 403d02ff9c..efd6cd514a 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/voter/MinuteBasedVoter.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/voter/MinuteBasedVoter.java @@ -1,33 +1,28 @@ package com.baeldung.roles.voter; import java.time.LocalDateTime; -import java.util.Collection; +import java.util.function.Supplier; -import org.springframework.security.access.AccessDecisionVoter; -import org.springframework.security.access.ConfigAttribute; +import org.springframework.security.authorization.AuthorizationDecision; +import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.web.access.intercept.RequestAuthorizationContext; -public class MinuteBasedVoter implements AccessDecisionVoter { +public class MinuteBasedVoter implements AuthorizationManager { @Override - public boolean supports(ConfigAttribute attribute) { - return true; + public void verify(Supplier authentication, RequestAuthorizationContext object) { + AuthorizationManager.super.verify(authentication, object); } @Override - public boolean supports(Class clazz) { - return true; - } - - @Override - public int vote(Authentication authentication, Object object, Collection collection) { - return authentication.getAuthorities() + public AuthorizationDecision check(Supplier authentication, RequestAuthorizationContext object) { + return authentication.get().getAuthorities() .stream() .map(GrantedAuthority::getAuthority) .filter(r -> "ROLE_USER".equals(r) && LocalDateTime.now().getMinute() % 2 != 0) - .findAny() - .map(s -> ACCESS_DENIED) - .orElse(ACCESS_ABSTAIN); + .findAny().map(s -> new AuthorizationDecision(false)) + .orElse(new AuthorizationDecision(true)); } } diff --git a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/voter/WebSecurityConfig.java b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/voter/WebSecurityConfig.java index 146853c18b..b6bad5fc77 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/voter/WebSecurityConfig.java +++ b/spring-security-modules/spring-security-web-boot-1/src/main/java/com/baeldung/roles/voter/WebSecurityConfig.java @@ -1,23 +1,19 @@ package com.baeldung.roles.voter; -import java.util.Arrays; -import java.util.List; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.security.access.AccessDecisionManager; -import org.springframework.security.access.AccessDecisionVoter; -import org.springframework.security.access.vote.AuthenticatedVoter; -import org.springframework.security.access.vote.RoleVoter; -import org.springframework.security.access.vote.UnanimousBased; +import org.springframework.security.authorization.AuthorizationManager; +import org.springframework.security.authorization.AuthorizationManagers; 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.configurers.AbstractAuthenticationFilterConfigurer; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.access.expression.WebExpressionVoter; +import org.springframework.security.web.access.intercept.RequestAuthorizationContext; @Configuration @EnableWebSecurity @@ -38,32 +34,20 @@ public class WebSecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http.csrf() - .disable() - .authorizeRequests() - .anyRequest() - .authenticated() - .accessDecisionManager(accessDecisionManager()) - .and() - .formLogin() - .permitAll() - .and() - .logout() - .permitAll() - .deleteCookies("JSESSIONID") - .logoutSuccessUrl("/login"); + http.csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> + authorizationManagerRequestMatcherRegistry.anyRequest().authenticated() + .anyRequest().access(accessDecisionManager())) + .formLogin(AbstractAuthenticationFilterConfigurer::permitAll) + .logout(httpSecurityLogoutConfigurer -> + httpSecurityLogoutConfigurer.permitAll().deleteCookies("JSESSIONID") + .logoutSuccessUrl("/login")); return http.build(); } @Bean - public AccessDecisionManager accessDecisionManager() { - List> decisionVoters = Arrays.asList( - new WebExpressionVoter(), - new RoleVoter(), - new AuthenticatedVoter(), - new MinuteBasedVoter()); - - return new UnanimousBased(decisionVoters); + public AuthorizationManager accessDecisionManager() { + return AuthorizationManagers.allOf(new MinuteBasedVoter()); } @Bean diff --git a/spring-security-modules/spring-security-web-boot-1/src/test/java/com/baeldung/relationships/SpringDataWithSecurityIntegrationTest.java b/spring-security-modules/spring-security-web-boot-1/src/test/java/com/baeldung/relationships/SpringDataWithSecurityIntegrationTest.java index 10c32de5d7..5750b0daa9 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/test/java/com/baeldung/relationships/SpringDataWithSecurityIntegrationTest.java +++ b/spring-security-modules/spring-security-web-boot-1/src/test/java/com/baeldung/relationships/SpringDataWithSecurityIntegrationTest.java @@ -11,9 +11,9 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; +import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -25,7 +25,7 @@ import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.jdbc.JdbcTestUtils; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; -import javax.servlet.ServletContext; +import jakarta.servlet.ServletContext; import java.util.Date; import java.util.List; @@ -83,7 +83,7 @@ public class SpringDataWithSecurityIntegrationTest { userRepository.updateLastLogin(new Date()); } - @Test(expected = InvalidDataAccessApiUsageException.class) + @Test(expected = SpelEvaluationException.class) public void givenNoAppUserInSecurityContext_whenUpdateLastLoginAttempted_shouldFail() { userRepository.updateLastLogin(new Date()); } @@ -104,7 +104,7 @@ public class SpringDataWithSecurityIntegrationTest { } while (page.hasNext()); } - @Test(expected = InvalidDataAccessApiUsageException.class) + @Test(expected = SpelEvaluationException.class) public void givenNoAppUser_whenPaginatedResultsRetrievalAttempted_shouldFail() { Page page = null; do { diff --git a/spring-security-modules/spring-security-web-boot-1/src/test/java/com/baeldung/roles/web/CustomUserDetailsServiceIntegrationTest.java b/spring-security-modules/spring-security-web-boot-1/src/test/java/com/baeldung/roles/web/CustomUserDetailsServiceIntegrationTest.java index 23ec605a36..085d5df551 100644 --- a/spring-security-modules/spring-security-web-boot-1/src/test/java/com/baeldung/roles/web/CustomUserDetailsServiceIntegrationTest.java +++ b/spring-security-modules/spring-security-web-boot-1/src/test/java/com/baeldung/roles/web/CustomUserDetailsServiceIntegrationTest.java @@ -6,13 +6,13 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import org.apache.http.HttpHeaders; import com.baeldung.roles.custom.Application; import com.baeldung.roles.custom.persistence.model.Foo; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.security.test.context.support.WithAnonymousUser; import org.springframework.security.test.context.support.WithUserDetails; diff --git a/testing-modules/groovy-spock/pom.xml b/testing-modules/groovy-spock/pom.xml index 7f456399fe..7920713810 100644 --- a/testing-modules/groovy-spock/pom.xml +++ b/testing-modules/groovy-spock/pom.xml @@ -15,6 +15,12 @@ 1.0.0-SNAPSHOT + + 2.4-M1-groovy-4.0 + 4.0.16 + 3.0.2 + + org.spockframework @@ -23,9 +29,10 @@ test - org.codehaus.groovy + org.apache.groovy groovy-all ${groovy-all.version} + pom @@ -39,18 +46,34 @@ compile - testCompile + compileTests + + + + ${project.basedir}/src/test/groovy + + **/*.groovy + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.2 + + src/test/groovy + + **/*Specification.groovy + **/*Test.groovy + + - - 1.3-groovy-2.4 - 2.4.7 - 1.5 - - \ No newline at end of file diff --git a/testing-modules/groovy-spock/src/main/java/mocks/Book.java b/testing-modules/groovy-spock/src/main/java/mocks/Book.java new file mode 100644 index 0000000000..b3f3f78606 --- /dev/null +++ b/testing-modules/groovy-spock/src/main/java/mocks/Book.java @@ -0,0 +1,11 @@ +package mocks; + +public class Book { + private String title; + private String author; + + Book(String title, String author) { + this.title = title; + this.author = author; + } +} diff --git a/testing-modules/groovy-spock/src/main/java/mocks/BookRepository.java b/testing-modules/groovy-spock/src/main/java/mocks/BookRepository.java new file mode 100644 index 0000000000..2628a6cab3 --- /dev/null +++ b/testing-modules/groovy-spock/src/main/java/mocks/BookRepository.java @@ -0,0 +1,5 @@ +package mocks; + +public interface BookRepository { + Book findById(Long id); +} \ No newline at end of file diff --git a/testing-modules/groovy-spock/src/main/java/mocks/BookService.java b/testing-modules/groovy-spock/src/main/java/mocks/BookService.java new file mode 100644 index 0000000000..750affec9e --- /dev/null +++ b/testing-modules/groovy-spock/src/main/java/mocks/BookService.java @@ -0,0 +1,13 @@ +package mocks; + +public class BookService { + private final BookRepository repository; + + public BookService(BookRepository repository) { + this.repository = repository; + } + + public Book getBookDetails(Long id) { + return repository.findById(id); + } +} diff --git a/testing-modules/groovy-spock/src/main/java/mocks/MessageService.java b/testing-modules/groovy-spock/src/main/java/mocks/MessageService.java new file mode 100644 index 0000000000..f9e4c5d938 --- /dev/null +++ b/testing-modules/groovy-spock/src/main/java/mocks/MessageService.java @@ -0,0 +1,7 @@ +package mocks; + +public class MessageService { + public String fetchMessage() { + return UtilityClass.getMessage(); + } +} \ No newline at end of file diff --git a/testing-modules/groovy-spock/src/main/java/mocks/ShoppingCart.java b/testing-modules/groovy-spock/src/main/java/mocks/ShoppingCart.java new file mode 100644 index 0000000000..94444c426f --- /dev/null +++ b/testing-modules/groovy-spock/src/main/java/mocks/ShoppingCart.java @@ -0,0 +1,26 @@ +package mocks; + +import java.util.HashMap; +import java.util.Map; + +public class ShoppingCart { + private final Map items = new HashMap<>(); + private double totalPrice = 0.0; + + public void addItem(String item, int quantity) { + items.put(item, items.getOrDefault(item, 0) + quantity); + totalPrice += quantity * 2.00; // Example pricing + } + + public int getTotalItems() { + return items.values().stream().mapToInt(Integer::intValue).sum(); + } + + public double getTotalPrice() { + return totalPrice; + } + + public boolean containsItem(String item) { + return items.containsKey(item); + } +} \ No newline at end of file diff --git a/testing-modules/groovy-spock/src/main/java/mocks/UtilityClass.java b/testing-modules/groovy-spock/src/main/java/mocks/UtilityClass.java new file mode 100644 index 0000000000..a218e9088c --- /dev/null +++ b/testing-modules/groovy-spock/src/main/java/mocks/UtilityClass.java @@ -0,0 +1,7 @@ +package mocks; + +public class UtilityClass { + public static String getMessage() { + return "Original Message"; + } +} \ No newline at end of file diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/ShoppingCartTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/ShoppingCartTest.groovy new file mode 100644 index 0000000000..116951988d --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/ShoppingCartTest.groovy @@ -0,0 +1,21 @@ +package extensions + +import mocks.ShoppingCart +import spock.lang.Specification + +class ShoppingCartTest extends Specification { + def "verify multiple properties of a ShoppingCart"() { + given: + ShoppingCart cart = new ShoppingCart() + cart.addItem("Apple", 3) + cart.addItem("Banana", 2) + + expect: + with(cart) { + totalItems == 5 + totalPrice == 10.00 + items.contains("Apple") + items.contains("Banana") + } + } +} \ No newline at end of file diff --git a/testing-modules/groovy-spock/src/test/groovy/mocks/BookServiceTest.groovy b/testing-modules/groovy-spock/src/test/groovy/mocks/BookServiceTest.groovy new file mode 100644 index 0000000000..b33cf6c015 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/mocks/BookServiceTest.groovy @@ -0,0 +1,25 @@ +package mocks + +import spock.lang.Specification + + +class BookServiceTest extends Specification { + def "should retrieve book details and verify method calls"() { + given: + def bookRepository = Mock(BookRepository) { + findById(1L) >> new Book("Effective Java", "Joshua Bloch") + findById(2L) >> null + } + def bookService = new BookService(bookRepository) + + when: + Book effectiveJava = bookService.getBookDetails(1L) + Book unknownBook = bookService.getBookDetails(2L) + + then: + 1 * bookRepository.findById(1L) + 1 * bookRepository.findById(2L) + effectiveJava.title == "Effective Java" + unknownBook == null + } +} \ No newline at end of file diff --git a/testing-modules/groovy-spock/src/test/groovy/mocks/MessageServiceTest.groovy b/testing-modules/groovy-spock/src/test/groovy/mocks/MessageServiceTest.groovy new file mode 100644 index 0000000000..7eeea90e41 --- /dev/null +++ b/testing-modules/groovy-spock/src/test/groovy/mocks/MessageServiceTest.groovy @@ -0,0 +1,20 @@ +package mocks + +import spock.lang.Specification + + +class MessageServiceTest extends Specification { + def "should use global mock for UtilityClass"() { + given: + def utilityMock = GroovySpy(UtilityClass, global: true) + utilityMock.getMessage() >> "Mocked Message" + + when: + MessageService service = new MessageService() + String message = service.fetchMessage() + + then: + 1 * utilityMock.getMessage() + message == "Mocked Message" + } +} \ No newline at end of file diff --git a/timefold-solver/README.md b/timefold-solver/README.md index 1abc4d4ca0..67fdd81bc1 100644 --- a/timefold-solver/README.md +++ b/timefold-solver/README.md @@ -4,3 +4,5 @@ This module contains articles about (Timefold Solver)[https://timefold.ai]. ### Relevant articles +- [A Guide to Timefold Solver for Employee Scheduling](https://www.baeldung.com/java-timefold-solver-guide) +