xjc
@@ -107,11 +114,12 @@
com.baeldung.boot.Application
- 3.1.3
- 1.17.2
- 1.10.0
+ 4.0.10
+ 1.19.7
+ 3.3.0
1.4.6
- 0.15.1
+ 0.15.3
+ 5.4.0
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/ProductEndpoint.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/ProductEndpoint.java
index c3ba5c04a8..16b976b152 100644
--- a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/ProductEndpoint.java
+++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/ProductEndpoint.java
@@ -1,21 +1,23 @@
package com.baeldung.webservice;
-import com.baeldung.webservice.generated.GetProductRequest;
-import com.baeldung.webservice.generated.GetProductResponse;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
+import com.baeldung.webservice.generated.GetProductRequest;
+import com.baeldung.webservice.generated.GetProductResponse;
+
@Endpoint
public class ProductEndpoint {
private static final String NAMESPACE_URI = "http://baeldung.com/spring-boot-web-service";
- @Autowired
- private ProductRepository productRepository;
+ private final ProductRepository productRepository;
+ public ProductEndpoint(ProductRepository productRepository) {
+ this.productRepository = productRepository;
+ }
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getProductRequest")
@ResponsePayload
diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/GetProductRequest.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/GetProductRequest.java
index d04302456b..f6b48af278 100644
--- a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/GetProductRequest.java
+++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/GetProductRequest.java
@@ -1,11 +1,11 @@
package com.baeldung.webservice.generated;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlElement;
+import jakarta.xml.bind.annotation.XmlRootElement;
+import jakarta.xml.bind.annotation.XmlType;
/**
@@ -13,17 +13,17 @@ import javax.xml.bind.annotation.XmlType;
*
* The following schema fragment specifies the expected content contained within this class.
*
- *
- * <complexType>
- * <complexContent>
- * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- * <sequence>
- * <element name="id" type="{http://www.w3.org/2001/XMLSchema}string"/>
- * </sequence>
- * </restriction>
- * </complexContent>
- * </complexType>
- *
+ * {@code
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * }
*
*
*/
diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/GetProductResponse.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/GetProductResponse.java
index f8fcaa094f..a2360d83eb 100644
--- a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/GetProductResponse.java
+++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/GetProductResponse.java
@@ -1,11 +1,11 @@
package com.baeldung.webservice.generated;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlElement;
+import jakarta.xml.bind.annotation.XmlRootElement;
+import jakarta.xml.bind.annotation.XmlType;
/**
@@ -13,17 +13,17 @@ import javax.xml.bind.annotation.XmlType;
*
* The following schema fragment specifies the expected content contained within this class.
*
- *
- * <complexType>
- * <complexContent>
- * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- * <sequence>
- * <element name="product" type="{http://baeldung.com/spring-boot-web-service}product"/>
- * </sequence>
- * </restriction>
- * </complexContent>
- * </complexType>
- *
+ * {@code
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * }
*
*
*/
diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/ObjectFactory.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/ObjectFactory.java
index 015ecc3f0a..e5877dd20b 100644
--- a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/ObjectFactory.java
+++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/ObjectFactory.java
@@ -1,7 +1,7 @@
package com.baeldung.webservice.generated;
-import javax.xml.bind.annotation.XmlRegistry;
+import jakarta.xml.bind.annotation.XmlRegistry;
/**
@@ -32,6 +32,8 @@ public class ObjectFactory {
/**
* Create an instance of {@link GetProductRequest }
*
+ * @return
+ * the new instance of {@link GetProductRequest }
*/
public GetProductRequest createGetProductRequest() {
return new GetProductRequest();
@@ -40,6 +42,8 @@ public class ObjectFactory {
/**
* Create an instance of {@link GetProductResponse }
*
+ * @return
+ * the new instance of {@link GetProductResponse }
*/
public GetProductResponse createGetProductResponse() {
return new GetProductResponse();
@@ -48,6 +52,8 @@ public class ObjectFactory {
/**
* Create an instance of {@link Product }
*
+ * @return
+ * the new instance of {@link Product }
*/
public Product createProduct() {
return new Product();
diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/Product.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/Product.java
index 5957aa44b4..f1d62d1489 100644
--- a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/Product.java
+++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/Product.java
@@ -1,10 +1,10 @@
package com.baeldung.webservice.generated;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlType;
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlElement;
+import jakarta.xml.bind.annotation.XmlType;
/**
@@ -12,18 +12,18 @@ import javax.xml.bind.annotation.XmlType;
*
* The following schema fragment specifies the expected content contained within this class.
*
- *
- * <complexType name="product">
- * <complexContent>
- * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- * <sequence>
- * <element name="id" type="{http://www.w3.org/2001/XMLSchema}string"/>
- * <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
- * </sequence>
- * </restriction>
- * </complexContent>
- * </complexType>
- *
+ * {@code
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * }
*
*
*/
diff --git a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/package-info.java b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/package-info.java
index 298ae9374b..fa8f2aeec5 100644
--- a/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/package-info.java
+++ b/spring-boot-modules/spring-boot-testing-2/src/main/java/com/baeldung/webservice/generated/package-info.java
@@ -1,2 +1,2 @@
-@javax.xml.bind.annotation.XmlSchema(namespace = "http://baeldung.com/spring-boot-web-service", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
+@jakarta.xml.bind.annotation.XmlSchema(namespace = "http://baeldung.com/spring-boot-web-service", elementFormDefault = jakarta.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.baeldung.webservice.generated;
diff --git a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/KeycloakTestContainers.java b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/KeycloakTestContainers.java
index 2a50a646c5..d68fae9cb5 100644
--- a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/KeycloakTestContainers.java
+++ b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/keycloaktestcontainers/KeycloakTestContainers.java
@@ -4,8 +4,6 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
-import javax.annotation.PostConstruct;
-
import org.apache.http.client.utils.URIBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -23,6 +21,7 @@ import org.springframework.web.reactive.function.client.WebClient;
import dasniko.testcontainers.keycloak.KeycloakContainer;
import io.restassured.RestAssured;
+import jakarta.annotation.PostConstruct;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public abstract class KeycloakTestContainers {
diff --git a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/webservice/ProductEndpointIntegrationTest.java b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/webservice/ProductEndpointIntegrationTest.java
index edd15090b8..0d58cfde17 100644
--- a/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/webservice/ProductEndpointIntegrationTest.java
+++ b/spring-boot-modules/spring-boot-testing-2/src/test/java/com/baeldung/webservice/ProductEndpointIntegrationTest.java
@@ -15,6 +15,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.webservices.server.WebServiceServerTest;
import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.test.server.MockWebServiceClient;
import org.springframework.xml.transform.StringSource;
@@ -22,6 +23,7 @@ import org.springframework.xml.transform.StringSource;
import com.baeldung.webservice.generated.Product;
@WebServiceServerTest
+@ComponentScan("com.baeldung.webservice")
class ProductEndpointIntegrationTest {
private static final Map NAMESPACE_MAPPING = createMapping();
diff --git a/spring-boot-modules/spring-boot-testing/pom.xml b/spring-boot-modules/spring-boot-testing/pom.xml
index 7643183fcb..28ce90d8ec 100644
--- a/spring-boot-modules/spring-boot-testing/pom.xml
+++ b/spring-boot-modules/spring-boot-testing/pom.xml
@@ -50,7 +50,7 @@
- it.ozimov
+ com.github.codemonstur
embedded-redis
${embedded-redis.version}
test
@@ -114,7 +114,7 @@
2.2.4
2.4-M1-groovy-4.0
3.0.0
- 0.7.2
+ 1.4.2
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-testing/src/test/java/com/baeldung/boot/embeddedRedis/TestRedisConfiguration.java b/spring-boot-modules/spring-boot-testing/src/test/java/com/baeldung/boot/embeddedRedis/TestRedisConfiguration.java
index 10e5d56857..f0ac4be194 100644
--- a/spring-boot-modules/spring-boot-testing/src/test/java/com/baeldung/boot/embeddedRedis/TestRedisConfiguration.java
+++ b/spring-boot-modules/spring-boot-testing/src/test/java/com/baeldung/boot/embeddedRedis/TestRedisConfiguration.java
@@ -1,18 +1,21 @@
package com.baeldung.boot.embeddedRedis;
-import com.baeldung.boot.embeddedRedis.configuration.RedisProperties;
+import java.io.IOException;
+
import org.springframework.boot.test.context.TestConfiguration;
-import redis.embedded.RedisServer;
+
+import com.baeldung.boot.embeddedRedis.configuration.RedisProperties;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
+import redis.embedded.RedisServer;
@TestConfiguration
public class TestRedisConfiguration {
private final RedisServer redisServer;
- public TestRedisConfiguration(final RedisProperties redisProperties) {
+ public TestRedisConfiguration(final RedisProperties redisProperties) throws IOException {
this.redisServer = new RedisServer(redisProperties.getRedisPort());
//Uncomment below if running on windows and can't start redis server
// this.redisServer = RedisServer.builder().setting("maxheap 200m").port(6379).setting("bind localhost").build();
@@ -20,12 +23,12 @@ public class TestRedisConfiguration {
}
@PostConstruct
- public void postConstruct() {
+ public void postConstruct() throws IOException {
redisServer.start();
}
@PreDestroy
- public void preDestroy() {
+ public void preDestroy() throws IOException {
redisServer.stop();
}
}
diff --git a/spring-boot-modules/spring-boot-testing/src/test/java/com/baeldung/boot/embeddedRedis/domain/repository/UserRepositoryIntegrationTest.java b/spring-boot-modules/spring-boot-testing/src/test/java/com/baeldung/boot/embeddedRedis/domain/repository/UserRepositoryIntegrationTest.java
index 9577ccf0e8..331801cc0a 100644
--- a/spring-boot-modules/spring-boot-testing/src/test/java/com/baeldung/boot/embeddedRedis/domain/repository/UserRepositoryIntegrationTest.java
+++ b/spring-boot-modules/spring-boot-testing/src/test/java/com/baeldung/boot/embeddedRedis/domain/repository/UserRepositoryIntegrationTest.java
@@ -1,26 +1,25 @@
package com.baeldung.boot.embeddedRedis.domain.repository;
-import com.baeldung.boot.embeddedRedis.TestRedisConfiguration;
-import com.baeldung.boot.embeddedRedis.domain.User;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.util.UUID;
-import static org.junit.Assert.assertNotNull;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import com.baeldung.boot.embeddedRedis.TestRedisConfiguration;
+import com.baeldung.boot.embeddedRedis.domain.User;
+
-@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestRedisConfiguration.class)
-public class UserRepositoryIntegrationTest {
+class UserRepositoryIntegrationTest {
@Autowired
private UserRepository userRepository;
@Test
- public void shouldSaveUser_toRedis() {
+ void shouldSaveUser_toRedis() {
final UUID id = UUID.randomUUID();
final User user = new User(id, "name");
diff --git a/spring-boot-modules/spring-caching-2/pom.xml b/spring-boot-modules/spring-caching-2/pom.xml
index ec9215aa32..95fae4a0ef 100644
--- a/spring-boot-modules/spring-caching-2/pom.xml
+++ b/spring-boot-modules/spring-caching-2/pom.xml
@@ -51,7 +51,7 @@
${caffeine.version}
- it.ozimov
+ com.github.codemonstur
embedded-redis
${embedded.redis.version}
@@ -65,7 +65,7 @@
- 0.7.3
+ 1.4.0
3.1.8
com.baeldung.caching.ttl.CachingTTLApplication
diff --git a/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/CacheConfig.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/CacheConfig.java
new file mode 100644
index 0000000000..576bcd97ab
--- /dev/null
+++ b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/CacheConfig.java
@@ -0,0 +1,71 @@
+package com.baeldung.caching.twolevelcache;
+
+import com.github.benmanes.caffeine.cache.Caffeine;
+
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.AnnotationCacheOperationSource;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cache.caffeine.CaffeineCache;
+import org.springframework.cache.interceptor.CacheInterceptor;
+import org.springframework.cache.interceptor.CacheOperationSource;
+import org.springframework.cache.support.SimpleCacheManager;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializationContext;
+
+import java.time.Duration;
+import java.util.Arrays;
+
+@Configuration
+@EnableCaching
+public class CacheConfig {
+
+ @Bean
+ @Primary
+ public CacheManager caffeineCacheManager(CaffeineCache caffeineCache) {
+ SimpleCacheManager manager = new SimpleCacheManager();
+ manager.setCaches(Arrays.asList(caffeineCache));
+ return manager;
+ }
+
+ @Bean
+ public CaffeineCache caffeineCacheConfig() {
+ return new CaffeineCache("customerCache", Caffeine.newBuilder()
+ .expireAfterWrite(Duration.ofSeconds(3))
+ .initialCapacity(1)
+ .maximumSize(2000)
+ .build());
+ }
+
+ @Bean
+ public CacheManager redisCacheManager(RedisConnectionFactory connectionFactory, RedisCacheConfiguration redisCacheConfiguration) {
+ return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(connectionFactory)
+ .withCacheConfiguration("customerCache", redisCacheConfiguration)
+ .build();
+ }
+
+ @Bean
+ public RedisCacheConfiguration cacheConfiguration() {
+ return RedisCacheConfiguration.defaultCacheConfig()
+ .entryTtl(Duration.ofMinutes(5))
+ .disableCachingNullValues()
+ .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
+ }
+
+ @Bean
+ public CacheInterceptor cacheInterceptor(CacheManager caffeineCacheManager, CacheOperationSource cacheOperationSource) {
+ CacheInterceptor interceptor = new CustomerCacheInterceptor(caffeineCacheManager);
+ interceptor.setCacheOperationSources(cacheOperationSource);
+ return interceptor;
+ }
+
+ @Bean
+ public CacheOperationSource cacheOperationSource() {
+ return new AnnotationCacheOperationSource();
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/Customer.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/Customer.java
new file mode 100644
index 0000000000..0b985d35f3
--- /dev/null
+++ b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/Customer.java
@@ -0,0 +1,25 @@
+package com.baeldung.caching.twolevelcache;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+@Data
+@Entity
+@AllArgsConstructor
+@NoArgsConstructor
+@Setter
+public class Customer implements Serializable {
+
+ @Id
+ private String id;
+
+ private String name;
+
+ private String email;
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/CustomerCacheInterceptor.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/CustomerCacheInterceptor.java
new file mode 100644
index 0000000000..f1a8dca0db
--- /dev/null
+++ b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/CustomerCacheInterceptor.java
@@ -0,0 +1,29 @@
+package com.baeldung.caching.twolevelcache;
+
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.interceptor.CacheInterceptor;
+import org.springframework.data.redis.cache.RedisCache;
+
+public class CustomerCacheInterceptor extends CacheInterceptor {
+
+ private final CacheManager caffeineCacheManager;
+
+ public CustomerCacheInterceptor(CacheManager caffeineCacheManager) {
+ this.caffeineCacheManager = caffeineCacheManager;
+ }
+
+ @Override
+ protected Cache.ValueWrapper doGet(Cache cache, Object key) {
+ Cache.ValueWrapper existingCacheValue = super.doGet(cache, key);
+
+ if (existingCacheValue != null && cache.getClass() == RedisCache.class) {
+ Cache caffeineCache = caffeineCacheManager.getCache(cache.getName());
+ if (caffeineCache != null) {
+ caffeineCache.putIfAbsent(key, existingCacheValue.get());
+ }
+ }
+
+ return existingCacheValue;
+ }
+}
diff --git a/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/CustomerRepository.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/CustomerRepository.java
new file mode 100644
index 0000000000..098112f152
--- /dev/null
+++ b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/CustomerRepository.java
@@ -0,0 +1,6 @@
+package com.baeldung.caching.twolevelcache;
+
+import org.springframework.data.repository.CrudRepository;
+
+public interface CustomerRepository extends CrudRepository {
+}
diff --git a/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/CustomerService.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/CustomerService.java
new file mode 100644
index 0000000000..088b66919c
--- /dev/null
+++ b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/CustomerService.java
@@ -0,0 +1,26 @@
+package com.baeldung.caching.twolevelcache;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.cache.annotation.Caching;
+import org.springframework.stereotype.Service;
+
+@Service
+public class CustomerService {
+
+ private final CustomerRepository customerRepository;
+
+ @Autowired
+ public CustomerService(CustomerRepository customerRepository) {
+ this.customerRepository = customerRepository;
+ }
+
+ @Caching(cacheable = {
+ @Cacheable(cacheNames = "customerCache", cacheManager = "caffeineCacheManager"),
+ @Cacheable(cacheNames = "customerCache", cacheManager = "redisCacheManager")
+ })
+ public Customer getCustomer(String id) {
+ return customerRepository.findById(id)
+ .orElseThrow(RuntimeException::new);
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/TwoLevelCacheApplication.java b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/TwoLevelCacheApplication.java
new file mode 100644
index 0000000000..9bc2c65e6e
--- /dev/null
+++ b/spring-boot-modules/spring-caching-2/src/main/java/com/baeldung/caching/twolevelcache/TwoLevelCacheApplication.java
@@ -0,0 +1,12 @@
+package com.baeldung.caching.twolevelcache;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class TwoLevelCacheApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(TwoLevelCacheApplication.class, args);
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-caching-2/src/main/resources/application.properties b/spring-boot-modules/spring-caching-2/src/main/resources/application.properties
index 38f3537d01..49bd715e43 100644
--- a/spring-boot-modules/spring-caching-2/src/main/resources/application.properties
+++ b/spring-boot-modules/spring-caching-2/src/main/resources/application.properties
@@ -11,3 +11,4 @@ caching.spring.hotelListTTL=43200
# Connection details
#spring.redis.host=localhost
#spring.redis.port=6379
+spring.main.allow-bean-definition-overriding=true
diff --git a/spring-boot-modules/spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java b/spring-boot-modules/spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java
index 8868edb74f..01740ba780 100644
--- a/spring-boot-modules/spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java
+++ b/spring-boot-modules/spring-caching-2/src/test/java/com/baeldung/caching/redis/ItemServiceCachingIntegrationTest.java
@@ -5,8 +5,6 @@ import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import java.util.Optional;
-
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -20,10 +18,12 @@ import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit.jupiter.SpringExtension;
+import redis.embedded.RedisServer;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
-import redis.embedded.RedisServer;
+import java.io.IOException;
+import java.util.Optional;
@Import({ CacheConfig.class, ItemService.class })
@ExtendWith(SpringExtension.class)
@@ -69,17 +69,17 @@ class ItemServiceCachingIntegrationTest {
private final RedisServer redisServer;
- public EmbeddedRedisConfiguration() {
+ public EmbeddedRedisConfiguration() throws IOException {
this.redisServer = new RedisServer();
}
@PostConstruct
- public void startRedis() {
+ public void startRedis() throws IOException {
redisServer.start();
}
@PreDestroy
- public void stopRedis() {
+ public void stopRedis() throws IOException {
this.redisServer.stop();
}
}
diff --git a/spring-boot-modules/spring-caching-2/src/test/java/com/baeldung/caching/twolevelcache/CustomerServiceCachingIntegrationTest.java b/spring-boot-modules/spring-caching-2/src/test/java/com/baeldung/caching/twolevelcache/CustomerServiceCachingIntegrationTest.java
new file mode 100644
index 0000000000..3db53198fc
--- /dev/null
+++ b/spring-boot-modules/spring-caching-2/src/test/java/com/baeldung/caching/twolevelcache/CustomerServiceCachingIntegrationTest.java
@@ -0,0 +1,124 @@
+package com.baeldung.caching.twolevelcache;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration;
+import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import redis.embedded.RedisServer;
+
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.PreDestroy;
+import java.io.IOException;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
+@Import({ CacheConfig.class,CustomerService.class })
+@ExtendWith(SpringExtension.class)
+@ImportAutoConfiguration(classes = { CacheAutoConfiguration.class, RedisAutoConfiguration.class })
+@EnableCaching
+class CustomerServiceCachingIntegrationTest {
+
+ @MockBean
+ private CustomerRepository customerRepository;
+
+ @Autowired
+ private CustomerService customerService;
+
+ @Autowired
+ private CacheManager redisCacheManager;
+
+ @Autowired
+ private CacheManager caffeineCacheManager;
+
+ @Test
+ void givenCustomerIsPresent_whenGetCustomerCalled_thenReturnCustomerAndCacheIt() {
+ String CUSTOMER_ID = "100";
+ Customer customer = new Customer(CUSTOMER_ID, "test", "test@mail.com");
+
+ given(customerRepository.findById(CUSTOMER_ID)).willReturn(Optional.of(customer));
+
+ Customer customerCacheMiss = customerService.getCustomer(CUSTOMER_ID);
+
+ assertThat(customerCacheMiss).isEqualTo(customer);
+ verify(customerRepository, times(1)).findById(CUSTOMER_ID);
+ assertThat(customerFromCaffeineCache(CUSTOMER_ID)).isEqualTo(customer);
+ assertThat(customerFromRedisCache(CUSTOMER_ID)).isEqualTo(customer);
+ }
+
+ @Test
+ void givenCustomerIsPresent_whenGetCustomerCalledTwice_thenReturnCustomerAndCacheIt() {
+ String CUSTOMER_ID = "101";
+ Customer customer = new Customer(CUSTOMER_ID, "test", "test@mail.com");
+ given(customerRepository.findById(CUSTOMER_ID)).willReturn(Optional.of(customer));
+
+ Customer customerCacheMiss = customerService.getCustomer(CUSTOMER_ID);
+ Customer customerCacheHit = customerService.getCustomer(CUSTOMER_ID);
+
+ assertThat(customerCacheMiss).isEqualTo(customer);
+ assertThat(customerCacheHit).isEqualTo(customer);
+ verify(customerRepository, times(1)).findById(CUSTOMER_ID);
+ assertThat(customerFromCaffeineCache(CUSTOMER_ID)).isEqualTo(customer);
+ assertThat(customerFromRedisCache(CUSTOMER_ID)).isEqualTo(customer);
+ }
+
+ @Test
+ void givenCustomerIsPresent_whenGetCustomerCalledTwiceAndFirstCacheExpired_thenReturnCustomerAndCacheIt() throws InterruptedException {
+ String CUSTOMER_ID = "102";
+ Customer customer = new Customer(CUSTOMER_ID, "test", "test@mail.com");
+ given(customerRepository.findById(CUSTOMER_ID)).willReturn(Optional.of(customer));
+
+ Customer customerCacheMiss = customerService.getCustomer(CUSTOMER_ID);
+ TimeUnit.SECONDS.sleep(3);
+ assertThat(customerFromCaffeineCache(CUSTOMER_ID)).isEqualTo(null);
+ Customer customerCacheHit = customerService.getCustomer(CUSTOMER_ID);
+
+ verify(customerRepository, times(1)).findById(CUSTOMER_ID);
+ assertThat(customerCacheMiss).isEqualTo(customer);
+ assertThat(customerCacheHit).isEqualTo(customer);
+ assertThat(customerFromCaffeineCache(CUSTOMER_ID)).isEqualTo(customer);
+ assertThat(customerFromRedisCache(CUSTOMER_ID)).isEqualTo(customer);
+ }
+
+ private Object customerFromRedisCache(String key) {
+ return redisCacheManager.getCache("customerCache").get(key) != null ?
+ redisCacheManager.getCache("customerCache").get(key).get() : null;
+ }
+
+ private Object customerFromCaffeineCache(String key) {
+ return caffeineCacheManager.getCache("customerCache").get(key) != null ?
+ caffeineCacheManager.getCache("customerCache").get(key).get() : null;
+ }
+
+ @TestConfiguration
+ static class EmbeddedRedisConfiguration {
+
+ private final RedisServer redisServer;
+
+ public EmbeddedRedisConfiguration() throws IOException {
+ this.redisServer = new RedisServer();
+ }
+
+ @PostConstruct
+ public void startRedis() throws IOException {
+ redisServer.start();
+ }
+
+ @PreDestroy
+ public void stopRedis() throws IOException {
+ this.redisServer.stop();
+ }
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-modules/pom.xml b/spring-cloud-modules/pom.xml
index 2613b9f9ce..187958fa6c 100644
--- a/spring-cloud-modules/pom.xml
+++ b/spring-cloud-modules/pom.xml
@@ -22,7 +22,8 @@
spring-cloud-hystrix
- spring-cloud-bootstrap
+
+
spring-cloud-ribbon-client
spring-cloud-zookeeper
spring-cloud-gateway
diff --git a/spring-cloud-modules/spring-cloud-bootstrap/config/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/config/pom.xml
index c1be447822..4831759fef 100644
--- a/spring-cloud-modules/spring-cloud-bootstrap/config/pom.xml
+++ b/spring-cloud-modules/spring-cloud-bootstrap/config/pom.xml
@@ -9,9 +9,9 @@
com.baeldung
- parent-boot-2
+ parent-boot-3
0.0.1-SNAPSHOT
- ../../../parent-boot-2
+ ../../../parent-boot-3
@@ -42,7 +42,7 @@
- 2021.0.7
+ 2022.0.4
\ No newline at end of file
diff --git a/spring-cloud-modules/spring-cloud-bootstrap/customer-service/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/customer-service/pom.xml
index da2dee97d5..c4d31138ad 100644
--- a/spring-cloud-modules/spring-cloud-bootstrap/customer-service/pom.xml
+++ b/spring-cloud-modules/spring-cloud-bootstrap/customer-service/pom.xml
@@ -11,9 +11,9 @@
com.baeldung
- parent-boot-2
+ parent-boot-3
0.0.1-SNAPSHOT
- ../../../parent-boot-2
+ ../../../parent-boot-3
diff --git a/spring-cloud-modules/spring-cloud-bootstrap/discovery/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/discovery/pom.xml
index 28c1a741a6..0527a232f7 100644
--- a/spring-cloud-modules/spring-cloud-bootstrap/discovery/pom.xml
+++ b/spring-cloud-modules/spring-cloud-bootstrap/discovery/pom.xml
@@ -9,9 +9,9 @@
com.baeldung
- parent-boot-2
+ parent-boot-3
0.0.1-SNAPSHOT
- ../../../parent-boot-2
+ ../../../parent-boot-3
@@ -54,7 +54,7 @@
- 2021.0.7
+ 2022.0.3
\ No newline at end of file
diff --git a/spring-cloud-modules/spring-cloud-bootstrap/discovery/src/main/java/com/baeldung/spring/cloud/bootstrap/discovery/SecurityConfig.java b/spring-cloud-modules/spring-cloud-bootstrap/discovery/src/main/java/com/baeldung/spring/cloud/bootstrap/discovery/SecurityConfig.java
index fa389ec6a3..b30515cdcf 100644
--- a/spring-cloud-modules/spring-cloud-bootstrap/discovery/src/main/java/com/baeldung/spring/cloud/bootstrap/discovery/SecurityConfig.java
+++ b/spring-cloud-modules/spring-cloud-bootstrap/discovery/src/main/java/com/baeldung/spring/cloud/bootstrap/discovery/SecurityConfig.java
@@ -4,41 +4,38 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
+import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
@Configuration
@EnableWebSecurity
@Order(1)
-public class SecurityConfig extends WebSecurityConfigurerAdapter {
+public class SecurityConfig {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("discUser").password("{noop}discPassword").roles("SYSTEM");
}
- @Override
protected void configure(HttpSecurity http) throws Exception {
- http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS).and().requestMatchers().antMatchers("/eureka/**").and().authorizeRequests().antMatchers("/eureka/**").hasRole("SYSTEM").anyRequest().denyAll().and().httpBasic().and().csrf()
- .disable();
+ http.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.ALWAYS)).authorizeHttpRequests(auth -> auth.requestMatchers("/eureka/**")).authorizeRequests(auth -> auth.requestMatchers("/eureka/**").hasRole("SYSTEM").anyRequest().denyAll()).httpBasic(
+ Customizer.withDefaults()).csrf(csrf -> csrf.disable());
}
@Configuration
// no order tag means this is the last security filter to be evaluated
- public static class AdminSecurityConfig extends WebSecurityConfigurerAdapter {
+ public static class AdminSecurityConfig {
- @Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication();
}
- @Override
protected void configure(HttpSecurity http) throws Exception {
- http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER).and().httpBasic().disable().authorizeRequests().antMatchers(HttpMethod.GET, "/").hasRole("ADMIN").antMatchers("/info", "/health").authenticated().anyRequest().denyAll()
- .and().csrf().disable();
+ http.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.NEVER)).httpBasic(basic -> basic.disable()).authorizeRequests().requestMatchers(HttpMethod.GET, "/").hasRole("ADMIN").requestMatchers("/info", "/health").authenticated().anyRequest().denyAll()
+ .and().csrf(csrf -> csrf.disable());
}
}
}
diff --git a/spring-cloud-modules/spring-cloud-bootstrap/gateway/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/gateway/pom.xml
index fa6735199f..b29d2eb760 100644
--- a/spring-cloud-modules/spring-cloud-bootstrap/gateway/pom.xml
+++ b/spring-cloud-modules/spring-cloud-bootstrap/gateway/pom.xml
@@ -9,9 +9,9 @@
com.baeldung
- parent-boot-2
+ parent-boot-3
0.0.1-SNAPSHOT
- ../../../parent-boot-2
+ ../../../parent-boot-3
@@ -55,18 +55,16 @@
org.springframework.boot
spring-boot-starter-data-redis
-
- org.springframework.cloud
- spring-cloud-starter-sleuth
-
-
- org.springframework.cloud
- spring-cloud-sleuth-zipkin
-
org.springframework.cloud
spring-cloud-starter-openfeign
+
+ io.rest-assured
+ rest-assured
+ ${rest-assured.version}
+ test
+
@@ -105,7 +103,8 @@
- 2021.0.7
+ 2022.0.4
+ 5.4.0
\ No newline at end of file
diff --git a/spring-cloud-modules/spring-cloud-bootstrap/order-service/order-server/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/order-service/order-server/pom.xml
index 85143b557e..e565a7dcab 100644
--- a/spring-cloud-modules/spring-cloud-bootstrap/order-service/order-server/pom.xml
+++ b/spring-cloud-modules/spring-cloud-bootstrap/order-service/order-server/pom.xml
@@ -20,6 +20,16 @@
1.0.0-SNAPSHOT
compile
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ provided
+
+
+ 1.18.30
+
+
\ No newline at end of file
diff --git a/spring-cloud-modules/spring-cloud-bootstrap/order-service/pom.xml b/spring-cloud-modules/spring-cloud-bootstrap/order-service/pom.xml
index 16366f5eb6..9adfbb4f54 100644
--- a/spring-cloud-modules/spring-cloud-bootstrap/order-service/pom.xml
+++ b/spring-cloud-modules/spring-cloud-bootstrap/order-service/pom.xml
@@ -11,9 +11,9 @@
com.baeldung
- parent-boot-2
+ parent-boot-3
0.0.1-SNAPSHOT
- ../../../parent-boot-2
+ ../../../parent-boot-3
@@ -81,16 +81,6 @@
exec
-