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 extends Arguments> 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 extends Arguments> 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 extends Arguments> 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 extends Arguments> 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)
+