diff --git a/algorithms-miscellaneous-3/README.md b/algorithms-miscellaneous-3/README.md
index 00b785c1b2..dd5bbac162 100644
--- a/algorithms-miscellaneous-3/README.md
+++ b/algorithms-miscellaneous-3/README.md
@@ -13,6 +13,5 @@ This module contains articles about algorithms. Some classes of algorithms, e.g.
- [Checking if a Java Graph has a Cycle](https://www.baeldung.com/java-graph-has-a-cycle)
- [A Guide to the Folding Technique in Java](https://www.baeldung.com/folding-hashing-technique)
- [Creating a Triangle with for Loops in Java](https://www.baeldung.com/java-print-triangle)
-- [Efficient Word Frequency Calculator in Java](https://www.baeldung.com/java-word-frequency)
- [The K-Means Clustering Algorithm in Java](https://www.baeldung.com/java-k-means-clustering-algorithm)
- More articles: [[<-- prev]](/algorithms-miscellaneous-2) [[next -->]](/algorithms-miscellaneous-4)
diff --git a/algorithms-miscellaneous-6/README.md b/algorithms-miscellaneous-6/README.md
new file mode 100644
index 0000000000..99be63d7ca
--- /dev/null
+++ b/algorithms-miscellaneous-6/README.md
@@ -0,0 +1,4 @@
+### Relevant Articles:
+
+- [Boruvka’s Algorithm for Minimum Spanning Trees](https://www.baeldung.com/java-boruvka-algorithm)
+- [Gradient Descent in Java](https://www.baeldung.com/java-gradient-descent)
diff --git a/apache-olingo/olingo2/README.md b/apache-olingo/olingo2/README.md
deleted file mode 100644
index 826cd0133e..0000000000
--- a/apache-olingo/olingo2/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-### Relevant Articles:
-
-- [Intro to OData with Olingo](https://www.baeldung.com/olingo)
diff --git a/atomikos/README.md b/atomikos/README.md
new file mode 100644
index 0000000000..19f2e871d4
--- /dev/null
+++ b/atomikos/README.md
@@ -0,0 +1,7 @@
+## Atomikos
+
+This module contains articles about Atomikos
+
+### Relevant Articles:
+
+- [Guide Transactions Using Atomikos]()
diff --git a/atomikos/pom.xml b/atomikos/pom.xml
new file mode 100644
index 0000000000..881adae074
--- /dev/null
+++ b/atomikos/pom.xml
@@ -0,0 +1,119 @@
+
+
+ 4.0.0
+ atomikos
+ atomikos
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+
+
+ com.atomikos
+ transactions-jdbc
+ ${atomikos-version}
+
+
+ com.atomikos
+ transactions-jms
+ ${atomikos-version}
+
+
+ com.atomikos
+ transactions-hibernate4
+ ${atomikos-version}
+
+
+ org.springframework
+ spring-context
+ ${spring-version}
+
+
+ org.springframework
+ spring-tx
+ ${spring-version}
+
+
+ org.springframework.data
+ spring-data-jpa
+ 1.11.23.RELEASE
+
+
+ org.springframework
+ spring-test
+ ${spring-version}
+ test
+
+
+ org.hibernate
+ hibernate-entitymanager
+ ${hibernate.version}
+ provided
+
+
+ javax.transaction
+ jta
+
+
+
+
+ org.apache.activemq
+ activemq-core
+ 5.7.0
+
+
+ org.apache.derby
+ derby
+ 10.8.1.2
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+
+ javax.transaction
+ jta
+ 1.1
+
+
+ org.apache.geronimo.specs
+ geronimo-jta_1.0.1B_spec
+ 1.0
+
+
+ javax.validation
+ validation-api
+ 2.0.1.Final
+
+
+ org.hibernate.validator
+ hibernate-validator
+ 6.1.2.Final
+
+
+ javax.el
+ javax.el-api
+ 3.0.0
+
+
+ org.glassfish.web
+ javax.el
+ 2.2.4
+
+
+
+
+ 5.0.6
+ 5.1.6.RELEASE
+ 5.4.3.Final
+
+
+
\ No newline at end of file
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/direct/Application.java b/atomikos/src/main/java/com/baeldung/atomikos/direct/Application.java
new file mode 100644
index 0000000000..c51ce70dde
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/direct/Application.java
@@ -0,0 +1,53 @@
+package com.baeldung.atomikos.direct;
+
+import java.sql.Connection;
+import java.sql.Statement;
+import java.util.UUID;
+
+import javax.sql.DataSource;
+
+import com.atomikos.icatch.jta.UserTransactionImp;
+
+public class Application {
+
+ private DataSource inventoryDataSource;
+ private DataSource orderDataSource;
+
+ public Application(DataSource inventoryDataSource, DataSource orderDataSource) {
+ this.inventoryDataSource = inventoryDataSource;
+ this.orderDataSource = orderDataSource;
+ }
+
+ public void placeOrder(String productId, int amount) throws Exception {
+
+ UserTransactionImp utx = new UserTransactionImp();
+ String orderId = UUID.randomUUID()
+ .toString();
+ boolean rollback = false;
+ try {
+ utx.begin();
+ Connection inventoryConnection = inventoryDataSource.getConnection();
+ Connection orderConnection = orderDataSource.getConnection();
+ Statement s1 = inventoryConnection.createStatement();
+ String q1 = "update Inventory set balance = balance - " + amount + " where productId ='" + productId + "'";
+ s1.executeUpdate(q1);
+ s1.close();
+ Statement s2 = orderConnection.createStatement();
+ String q2 = "insert into Orders values ( '" + orderId + "', '" + productId + "', " + amount + " )";
+ s2.executeUpdate(q2);
+ s2.close();
+ inventoryConnection.close();
+ orderConnection.close();
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ rollback = true;
+ } finally {
+ if (!rollback)
+ utx.commit();
+ else
+ utx.rollback();
+ }
+
+ }
+
+}
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/Application.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/Application.java
new file mode 100644
index 0000000000..b480e68d8d
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/Application.java
@@ -0,0 +1,41 @@
+package com.baeldung.atomikos.spring;
+
+import java.sql.Connection;
+import java.sql.Statement;
+import java.util.UUID;
+
+import javax.sql.DataSource;
+
+import org.springframework.transaction.annotation.Transactional;
+
+public class Application {
+
+ private DataSource inventoryDataSource;
+ private DataSource orderDataSource;
+
+ public Application(DataSource inventoryDataSource, DataSource orderDataSource) {
+ this.inventoryDataSource = inventoryDataSource;
+ this.orderDataSource = orderDataSource;
+ }
+
+ @Transactional(rollbackFor = Exception.class)
+ public void placeOrder(String productId, int amount) throws Exception {
+
+ String orderId = UUID.randomUUID()
+ .toString();
+ Connection inventoryConnection = inventoryDataSource.getConnection();
+ Connection orderConnection = orderDataSource.getConnection();
+ Statement s1 = inventoryConnection.createStatement();
+ String q1 = "update Inventory set balance = balance - " + amount + " where productId ='" + productId + "'";
+ s1.executeUpdate(q1);
+ s1.close();
+ Statement s2 = orderConnection.createStatement();
+ String q2 = "insert into Orders values ( '" + orderId + "', '" + productId + "', " + amount + " )";
+ s2.executeUpdate(q2);
+ s2.close();
+ inventoryConnection.close();
+ orderConnection.close();
+
+ }
+
+}
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/config/Config.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/config/Config.java
new file mode 100644
index 0000000000..c6ef83c4ca
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/config/Config.java
@@ -0,0 +1,68 @@
+package com.baeldung.atomikos.spring.config;
+
+import java.util.Properties;
+
+import javax.transaction.SystemException;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+import org.springframework.transaction.jta.JtaTransactionManager;
+
+import com.atomikos.icatch.jta.UserTransactionManager;
+import com.atomikos.jdbc.AtomikosDataSourceBean;
+import com.baeldung.atomikos.spring.Application;
+
+@Configuration
+@EnableTransactionManagement
+public class Config {
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public AtomikosDataSourceBean inventoryDataSource() {
+ AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
+ dataSource.setLocalTransactionMode(true);
+ dataSource.setUniqueResourceName("db1");
+ dataSource.setXaDataSourceClassName("org.apache.derby.jdbc.EmbeddedXADataSource");
+ Properties xaProperties = new Properties();
+ xaProperties.put("databaseName", "db1");
+ xaProperties.put("createDatabase", "create");
+ dataSource.setXaProperties(xaProperties);
+ dataSource.setPoolSize(10);
+ return dataSource;
+ }
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public AtomikosDataSourceBean orderDataSource() {
+ AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
+ dataSource.setLocalTransactionMode(true);
+ dataSource.setUniqueResourceName("db2");
+ dataSource.setXaDataSourceClassName("org.apache.derby.jdbc.EmbeddedXADataSource");
+ Properties xaProperties = new Properties();
+ xaProperties.put("databaseName", "db2");
+ xaProperties.put("createDatabase", "create");
+ dataSource.setXaProperties(xaProperties);
+ dataSource.setPoolSize(10);
+ return dataSource;
+ }
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public UserTransactionManager userTransactionManager() throws SystemException {
+ UserTransactionManager userTransactionManager = new UserTransactionManager();
+ userTransactionManager.setTransactionTimeout(300);
+ userTransactionManager.setForceShutdown(true);
+ return userTransactionManager;
+ }
+
+ @Bean
+ public JtaTransactionManager jtaTransactionManager() throws SystemException {
+ JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
+ jtaTransactionManager.setTransactionManager(userTransactionManager());
+ jtaTransactionManager.setUserTransaction(userTransactionManager());
+ return jtaTransactionManager;
+ }
+
+ @Bean
+ public Application application() {
+ return new Application(inventoryDataSource(), orderDataSource());
+ }
+}
\ No newline at end of file
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/Application.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/Application.java
new file mode 100644
index 0000000000..cf1fef2cd8
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/Application.java
@@ -0,0 +1,48 @@
+package com.baeldung.atomikos.spring.jpa;
+
+import java.util.Set;
+import java.util.UUID;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baeldung.atomikos.spring.jpa.inventory.Inventory;
+import com.baeldung.atomikos.spring.jpa.inventory.InventoryRepository;
+import com.baeldung.atomikos.spring.jpa.order.Order;
+import com.baeldung.atomikos.spring.jpa.order.OrderRepository;
+
+public class Application {
+
+ @Autowired
+ private InventoryRepository inventoryRepository;
+
+ @Autowired
+ private OrderRepository orderRepository;
+
+ @Transactional(rollbackFor = Exception.class)
+ public void placeOrder(String productId, int amount) throws Exception {
+
+ String orderId = UUID.randomUUID()
+ .toString();
+ Inventory inventory = inventoryRepository.findOne(productId);
+ inventory.setBalance(inventory.getBalance() - amount);
+ inventoryRepository.save(inventory);
+ Order order = new Order();
+ order.setOrderId(orderId);
+ order.setProductId(productId);
+ order.setAmount(new Long(amount));
+ ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
+ Validator validator = factory.getValidator();
+ Set> violations = validator.validate(order);
+ if (violations.size() > 0)
+ throw new Exception("Invalid instance of an order.");
+ orderRepository.save(order);
+
+ }
+
+}
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/config/Config.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/config/Config.java
new file mode 100644
index 0000000000..6716f19576
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/config/Config.java
@@ -0,0 +1,38 @@
+package com.baeldung.atomikos.spring.jpa.config;
+
+import javax.transaction.SystemException;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+import org.springframework.transaction.jta.JtaTransactionManager;
+
+import com.atomikos.icatch.jta.UserTransactionManager;
+import com.baeldung.atomikos.spring.jpa.Application;
+
+@Configuration
+@EnableTransactionManagement
+public class Config {
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public UserTransactionManager userTransactionManager() throws SystemException {
+ UserTransactionManager userTransactionManager = new UserTransactionManager();
+ userTransactionManager.setTransactionTimeout(300);
+ userTransactionManager.setForceShutdown(true);
+ return userTransactionManager;
+ }
+
+ @Bean
+ public JtaTransactionManager transactionManager() throws SystemException {
+ JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
+ jtaTransactionManager.setTransactionManager(userTransactionManager());
+ jtaTransactionManager.setUserTransaction(userTransactionManager());
+ return jtaTransactionManager;
+ }
+
+ @Bean
+ public Application application() {
+ return new Application();
+ }
+
+}
\ No newline at end of file
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/Inventory.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/Inventory.java
new file mode 100644
index 0000000000..999879218c
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/Inventory.java
@@ -0,0 +1,31 @@
+package com.baeldung.atomikos.spring.jpa.inventory;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "INVENTORY")
+public class Inventory {
+
+ @Id
+ private String productId;
+ private Long balance;
+
+ public String getProductId() {
+ return productId;
+ }
+
+ public void setProductId(String productId) {
+ this.productId = productId;
+ }
+
+ public Long getBalance() {
+ return balance;
+ }
+
+ public void setBalance(Long balance) {
+ this.balance = balance;
+ }
+
+}
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/InventoryConfig.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/InventoryConfig.java
new file mode 100644
index 0000000000..5301ad6ff2
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/InventoryConfig.java
@@ -0,0 +1,53 @@
+package com.baeldung.atomikos.spring.jpa.inventory;
+
+import java.util.Properties;
+
+import javax.persistence.EntityManagerFactory;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
+
+import com.atomikos.jdbc.AtomikosDataSourceBean;
+
+@Configuration
+@EnableJpaRepositories(basePackages = "com.baeldung.atomikos.spring.jpa.inventory", entityManagerFactoryRef = "inventoryEntityManager", transactionManagerRef = "transactionManager")
+public class InventoryConfig {
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public AtomikosDataSourceBean inventoryDataSource() {
+ AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
+ dataSource.setLocalTransactionMode(true);
+ dataSource.setUniqueResourceName("db1");
+ dataSource.setXaDataSourceClassName("org.apache.derby.jdbc.EmbeddedXADataSource");
+ Properties xaProperties = new Properties();
+ xaProperties.put("databaseName", "db1");
+ xaProperties.put("createDatabase", "create");
+ dataSource.setXaProperties(xaProperties);
+ dataSource.setPoolSize(10);
+ return dataSource;
+ }
+
+ @Bean
+ public EntityManagerFactory inventoryEntityManager() {
+ HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
+ LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
+ factory.setJpaVendorAdapter(vendorAdapter);
+ factory.setPackagesToScan("com.baeldung.atomikos.spring.jpa.inventory");
+ factory.setDataSource(inventoryDataSource());
+ Properties jpaProperties = new Properties();
+ //jpaProperties.put("hibernate.show_sql", "true");
+ //jpaProperties.put("hibernate.format_sql", "true");
+ jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyDialect");
+ jpaProperties.put("hibernate.current_session_context_class", "jta");
+ jpaProperties.put("javax.persistence.transactionType", "jta");
+ jpaProperties.put("hibernate.transaction.manager_lookup_class", "com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup");
+ jpaProperties.put("hibernate.hbm2ddl.auto", "create-drop");
+ factory.setJpaProperties(jpaProperties);
+ factory.afterPropertiesSet();
+ return factory.getObject();
+ }
+
+}
\ No newline at end of file
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/InventoryRepository.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/InventoryRepository.java
new file mode 100644
index 0000000000..c3868e51bf
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/inventory/InventoryRepository.java
@@ -0,0 +1,9 @@
+package com.baeldung.atomikos.spring.jpa.inventory;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface InventoryRepository extends JpaRepository {
+
+}
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/Order.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/Order.java
new file mode 100644
index 0000000000..4b9ae2dd1d
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/Order.java
@@ -0,0 +1,42 @@
+package com.baeldung.atomikos.spring.jpa.order;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.validation.constraints.Max;
+
+@Entity
+@Table(name = "ORDERS")
+public class Order {
+
+ @Id
+ private String orderId;
+ private String productId;
+ @Max(5)
+ private Long amount;
+
+ public String getOrderId() {
+ return orderId;
+ }
+
+ public void setOrderId(String orderId) {
+ this.orderId = orderId;
+ }
+
+ public String getProductId() {
+ return productId;
+ }
+
+ public void setProductId(String productId) {
+ this.productId = productId;
+ }
+
+ public Long getAmount() {
+ return amount;
+ }
+
+ public void setAmount(Long amount) {
+ this.amount = amount;
+ }
+
+}
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/OrderConfig.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/OrderConfig.java
new file mode 100644
index 0000000000..b4274bb64c
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/OrderConfig.java
@@ -0,0 +1,53 @@
+package com.baeldung.atomikos.spring.jpa.order;
+
+import java.util.Properties;
+
+import javax.persistence.EntityManagerFactory;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
+
+import com.atomikos.jdbc.AtomikosDataSourceBean;
+
+@Configuration
+@EnableJpaRepositories(basePackages = "com.baeldung.atomikos.spring.jpa.order", entityManagerFactoryRef = "orderEntityManager", transactionManagerRef = "transactionManager")
+public class OrderConfig {
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public AtomikosDataSourceBean orderDataSource() {
+ AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
+ dataSource.setLocalTransactionMode(true);
+ dataSource.setUniqueResourceName("db2");
+ dataSource.setXaDataSourceClassName("org.apache.derby.jdbc.EmbeddedXADataSource");
+ Properties xaProperties = new Properties();
+ xaProperties.put("databaseName", "db2");
+ xaProperties.put("createDatabase", "create");
+ dataSource.setXaProperties(xaProperties);
+ dataSource.setPoolSize(10);
+ return dataSource;
+ }
+
+ @Bean
+ public EntityManagerFactory orderEntityManager() {
+ HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
+ LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
+ factory.setJpaVendorAdapter(vendorAdapter);
+ factory.setPackagesToScan("com.baeldung.atomikos.spring.jpa.order");
+ factory.setDataSource(orderDataSource());
+ Properties jpaProperties = new Properties();
+ //jpaProperties.put("hibernate.show_sql", "true");
+ //jpaProperties.put("hibernate.format_sql", "true");
+ jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyDialect");
+ jpaProperties.put("hibernate.current_session_context_class", "jta");
+ jpaProperties.put("javax.persistence.transactionType", "jta");
+ jpaProperties.put("hibernate.transaction.manager_lookup_class", "com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup");
+ jpaProperties.put("hibernate.hbm2ddl.auto", "create-drop");
+ factory.setJpaProperties(jpaProperties);
+ factory.afterPropertiesSet();
+ return factory.getObject();
+ }
+
+}
\ No newline at end of file
diff --git a/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/OrderRepository.java b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/OrderRepository.java
new file mode 100644
index 0000000000..2d5610ebca
--- /dev/null
+++ b/atomikos/src/main/java/com/baeldung/atomikos/spring/jpa/order/OrderRepository.java
@@ -0,0 +1,9 @@
+package com.baeldung.atomikos.spring.jpa.order;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface OrderRepository extends JpaRepository {
+
+}
diff --git a/atomikos/src/main/resources/logback.xml b/atomikos/src/main/resources/logback.xml
new file mode 100644
index 0000000000..7d900d8ea8
--- /dev/null
+++ b/atomikos/src/main/resources/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/atomikos/src/main/resources/schema.sql b/atomikos/src/main/resources/schema.sql
new file mode 100644
index 0000000000..5136ad1284
--- /dev/null
+++ b/atomikos/src/main/resources/schema.sql
@@ -0,0 +1,10 @@
+CREATE TABLE INVENTORY (
+ productId VARCHAR PRIMARY KEY,
+ balance INT
+);
+
+CREATE TABLE ORDERS (
+ orderId VARCHAR PRIMARY KEY,
+ productId VARCHAR,
+ amount INT NOT NULL CHECK (amount <= 5)
+);
\ No newline at end of file
diff --git a/atomikos/src/main/resources/transactions.properties b/atomikos/src/main/resources/transactions.properties
new file mode 100644
index 0000000000..8e027032fa
--- /dev/null
+++ b/atomikos/src/main/resources/transactions.properties
@@ -0,0 +1 @@
+com.atomikos.icatch.file=logs
\ No newline at end of file
diff --git a/atomikos/src/test/java/com/baeldung/atomikos/direct/ApplicationUnitTest.java b/atomikos/src/test/java/com/baeldung/atomikos/direct/ApplicationUnitTest.java
new file mode 100644
index 0000000000..1a467807ba
--- /dev/null
+++ b/atomikos/src/test/java/com/baeldung/atomikos/direct/ApplicationUnitTest.java
@@ -0,0 +1,118 @@
+package com.baeldung.atomikos.direct;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+import java.util.UUID;
+
+import javax.sql.DataSource;
+
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.atomikos.icatch.jta.UserTransactionImp;
+import com.atomikos.jdbc.AtomikosDataSourceBean;
+
+public class ApplicationUnitTest {
+
+ private static DataSource inventoryDataSource;
+ private static DataSource orderDataSource;
+
+ private static String productId = UUID.randomUUID()
+ .toString();
+
+ @Test
+ @Ignore
+ public void testPlaceOrderSuccess() throws Exception {
+ int amount = 1;
+ long initialBalance = getBalance(inventoryDataSource, productId);
+ Application application = new Application(inventoryDataSource, orderDataSource);
+ application.placeOrder(productId, amount);
+ long finalBalance = getBalance(inventoryDataSource, productId);
+ assertEquals(initialBalance - amount, finalBalance);
+ }
+
+ @Test
+ @Ignore
+ public void testPlaceOrderFailure() throws Exception {
+ int amount = 10;
+ long initialBalance = getBalance(inventoryDataSource, productId);
+ Application application = new Application(inventoryDataSource, orderDataSource);
+ application.placeOrder(productId, amount);
+ long finalBalance = getBalance(inventoryDataSource, productId);
+ assertEquals(initialBalance, finalBalance);
+ }
+
+ @BeforeClass
+ public static void setUp() throws SQLException {
+
+ inventoryDataSource = getDataSource("db1");
+ orderDataSource = getDataSource("db2");
+ Connection inventoryConnection = inventoryDataSource.getConnection();
+ Connection orderConnection = orderDataSource.getConnection();
+ String createInventoryTable = "create table Inventory ( " + " productId VARCHAR ( 100 ) PRIMARY KEY, balance INT )";
+ String createInventoryRow = "insert into Inventory values ( '" + productId + "', 10000 )";
+ Statement s1 = inventoryConnection.createStatement();
+ try {
+ s1.executeUpdate(createInventoryTable);
+ } catch (Exception e) {
+ System.out.println("Inventory table exists");
+ }
+ try {
+ s1.executeUpdate(createInventoryRow);
+ } catch (Exception e) {
+ System.out.println("Product row exists");
+ }
+ s1.close();
+ String createOrderTable = "create table Orders ( orderId VARCHAR ( 100 ) PRIMARY KEY, productId VARCHAR ( 100 ), amount INT NOT NULL CHECK (amount <= 5) )";
+ Statement s2 = orderConnection.createStatement();
+ try {
+ s2.executeUpdate(createOrderTable);
+ } catch (Exception e) {
+ System.out.println("Orders table exists");
+ }
+ s2.close();
+ inventoryConnection.close();
+ orderConnection.close();
+ }
+
+ private static DataSource getDataSource(String db) {
+
+ DataSource ds;
+ AtomikosDataSourceBean ads = new AtomikosDataSourceBean();
+ ads.setXaDataSourceClassName("org.apache.derby.jdbc.EmbeddedXADataSource");
+ Properties properties = new Properties();
+ properties.put("databaseName", db);
+ properties.put("createDatabase", "create");
+ ads.setXaProperties(properties);
+ ads.setUniqueResourceName(db);
+ ads.setPoolSize(10); // optional
+ ads.setBorrowConnectionTimeout(10); // optional
+ ds = ads;
+ return ds;
+
+ }
+
+ private static long getBalance(DataSource inventoryDataSource, String productId) throws Exception {
+
+ UserTransactionImp utx = new UserTransactionImp();
+ utx.begin();
+ Connection inventoryConnection = inventoryDataSource.getConnection();
+ Statement s1 = inventoryConnection.createStatement();
+ String q1 = "select balance from Inventory where productId='" + productId + "'";
+ ResultSet rs1 = s1.executeQuery(q1);
+ if (rs1 == null || !rs1.next())
+ throw new Exception("Product not found: " + productId);
+ long balance = rs1.getLong(1);
+ inventoryConnection.close();
+ utx.commit();
+ return balance;
+
+ }
+
+}
diff --git a/atomikos/src/test/java/com/baeldung/atomikos/spring/ApplicationUnitTest.java b/atomikos/src/test/java/com/baeldung/atomikos/spring/ApplicationUnitTest.java
new file mode 100644
index 0000000000..0c9392eac4
--- /dev/null
+++ b/atomikos/src/test/java/com/baeldung/atomikos/spring/ApplicationUnitTest.java
@@ -0,0 +1,108 @@
+package com.baeldung.atomikos.spring;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import javax.sql.DataSource;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import com.baeldung.atomikos.spring.config.Config;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = { Config.class })
+public class ApplicationUnitTest {
+
+ private static String productId = UUID.randomUUID()
+ .toString();
+
+ @Autowired
+ Application application;
+
+ @Autowired
+ DataSource inventoryDataSource;
+
+ @Autowired
+ DataSource orderDataSource;
+
+ @Test
+ @Ignore
+ public void testPlaceOrderSuccess() throws Exception {
+ int amount = 1;
+ long initialBalance = getBalance(inventoryDataSource, productId);
+ application.placeOrder(productId, amount);
+ long finalBalance = getBalance(inventoryDataSource, productId);
+ assertEquals(initialBalance - amount, finalBalance);
+ }
+
+ @Test
+ @Ignore
+ public void testPlaceOrderFailure() throws Exception {
+ int amount = 10;
+ long initialBalance = getBalance(inventoryDataSource, productId);
+ try {
+ application.placeOrder(productId, amount);
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ }
+ long finalBalance = getBalance(inventoryDataSource, productId);
+ assertEquals(initialBalance, finalBalance);
+ }
+
+ @Before
+ public void setUp() throws SQLException {
+
+ Connection inventoryConnection = inventoryDataSource.getConnection();
+ Connection orderConnection = orderDataSource.getConnection();
+ String createInventoryTable = "create table Inventory ( " + " productId VARCHAR ( 100 ) PRIMARY KEY, balance INT )";
+ String createInventoryRow = "insert into Inventory values ( '" + productId + "', 10000 )";
+ Statement s1 = inventoryConnection.createStatement();
+ try {
+ s1.executeUpdate(createInventoryTable);
+ } catch (Exception e) {
+ System.out.println("Inventory table exists");
+ }
+ try {
+ s1.executeUpdate(createInventoryRow);
+ } catch (Exception e) {
+ System.out.println("Product row exists");
+ }
+ s1.close();
+ String createOrderTable = "create table Orders ( orderId VARCHAR ( 100 ) PRIMARY KEY, productId VARCHAR ( 100 ), amount INT NOT NULL CHECK (amount <= 5) )";
+ Statement s2 = orderConnection.createStatement();
+ try {
+ s2.executeUpdate(createOrderTable);
+ } catch (Exception e) {
+ System.out.println("Orders table exists");
+ }
+ s2.close();
+ inventoryConnection.close();
+ orderConnection.close();
+ }
+
+ private static long getBalance(DataSource inventoryDataSource, String productId) throws Exception {
+
+ Connection inventoryConnection = inventoryDataSource.getConnection();
+ Statement s1 = inventoryConnection.createStatement();
+ String q1 = "select balance from Inventory where productId='" + productId + "'";
+ ResultSet rs1 = s1.executeQuery(q1);
+ if (rs1 == null || !rs1.next())
+ throw new Exception("Product not found: " + productId);
+ long balance = rs1.getLong(1);
+ inventoryConnection.close();
+ return balance;
+
+ }
+
+}
diff --git a/atomikos/src/test/java/com/baeldung/atomikos/spring/jpa/ApplicationUnitTest.java b/atomikos/src/test/java/com/baeldung/atomikos/spring/jpa/ApplicationUnitTest.java
new file mode 100644
index 0000000000..e6a3c1982c
--- /dev/null
+++ b/atomikos/src/test/java/com/baeldung/atomikos/spring/jpa/ApplicationUnitTest.java
@@ -0,0 +1,80 @@
+package com.baeldung.atomikos.spring.jpa;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.sql.SQLException;
+import java.util.UUID;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import com.baeldung.atomikos.spring.jpa.config.Config;
+import com.baeldung.atomikos.spring.jpa.inventory.Inventory;
+import com.baeldung.atomikos.spring.jpa.inventory.InventoryConfig;
+import com.baeldung.atomikos.spring.jpa.inventory.InventoryRepository;
+import com.baeldung.atomikos.spring.jpa.order.OrderConfig;
+import com.baeldung.atomikos.spring.jpa.order.OrderRepository;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = { Config.class, InventoryConfig.class, OrderConfig.class })
+public class ApplicationUnitTest {
+
+ private static String productId = UUID.randomUUID()
+ .toString();
+
+ @Autowired
+ Application application;
+
+ @Autowired
+ InventoryRepository inventoryRepository;
+
+ @Autowired
+ OrderRepository orderRepository;
+
+ @Test
+ @Ignore
+ public void testPlaceOrderSuccess() throws Exception {
+ int amount = 1;
+ long initialBalance = getBalance(inventoryRepository, productId);
+ application.placeOrder(productId, amount);
+ long finalBalance = getBalance(inventoryRepository, productId);
+ assertEquals(initialBalance - amount, finalBalance);
+ }
+
+ @Test
+ @Ignore
+ public void testPlaceOrderFailure() throws Exception {
+ int amount = 10;
+ long initialBalance = getBalance(inventoryRepository, productId);
+ try {
+ application.placeOrder(productId, amount);
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ }
+ long finalBalance = getBalance(inventoryRepository, productId);
+ assertEquals(initialBalance, finalBalance);
+ }
+
+ @Before
+ public void setUp() throws SQLException {
+
+ Inventory inventory = new Inventory();
+ inventory.setProductId(productId);
+ inventory.setBalance(new Long(10000));
+ inventoryRepository.save(inventory);
+
+ }
+
+ private static long getBalance(InventoryRepository inventoryRepository, String productId) throws Exception {
+
+ return inventoryRepository.findOne(productId)
+ .getBalance();
+
+ }
+
+}
diff --git a/atomikos/src/test/resources/logback.xml b/atomikos/src/test/resources/logback.xml
new file mode 100644
index 0000000000..7d900d8ea8
--- /dev/null
+++ b/atomikos/src/test/resources/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/atomikos/src/test/resources/transactions.properties b/atomikos/src/test/resources/transactions.properties
new file mode 100644
index 0000000000..8e027032fa
--- /dev/null
+++ b/atomikos/src/test/resources/transactions.properties
@@ -0,0 +1 @@
+com.atomikos.icatch.file=logs
\ No newline at end of file
diff --git a/cas/cas-server/README.md b/cas/cas-server/README.md
deleted file mode 100644
index b224738732..0000000000
--- a/cas/cas-server/README.md
+++ /dev/null
@@ -1,146 +0,0 @@
-CAS Overlay Template [![Build Status](https://travis-ci.org/apereo/cas-overlay-template.svg?branch=master)](https://travis-ci.org/apereo/cas-overlay-template)
-=======================
-
-Generic CAS WAR overlay to exercise the latest versions of CAS. This overlay could be freely used as a starting template for local CAS war overlays.
-
-# Versions
-
-- CAS `6.1.x`
-- JDK `11`
-
-# Overview
-
-To build the project, use:
-
-```bash
-# Use --refresh-dependencies to force-update SNAPSHOT versions
-./gradlew[.bat] clean build
-```
-
-To see what commands are available to the build script, run:
-
-```bash
-./gradlew[.bat] tasks
-```
-
-To launch into the CAS command-line shell:
-
-```bash
-./gradlew[.bat] downloadShell runShell
-```
-
-To fetch and overlay a CAS resource or view, use:
-
-```bash
-./gradlew[.bat] getResource -PresourceName=[resource-name]
-```
-
-To list all available CAS views and templates:
-
-```bash
-./gradlew[.bat] listTemplateViews
-```
-
-To unzip and explode the CAS web application file and the internal resources jar:
-
-```bash
-./gradlew[.bat] explodeWar
-```
-
-# Configuration
-
-- The `etc` directory contains the configuration files and directories that need to be copied to `/etc/cas/config`.
-
-```bash
-./gradlew[.bat] copyCasConfiguration
-```
-
-- The specifics of the build are controlled using the `gradle.properties` file.
-
-## Adding Modules
-
-CAS modules may be specified under the `dependencies` block of the [Gradle build script](build.gradle):
-
-```gradle
-dependencies {
- compile "org.apereo.cas:cas-server-some-module:${project.casVersion}"
- ...
-}
-```
-
-To collect the list of all project modules and dependencies:
-
-```bash
-./gradlew[.bat] allDependencies
-```
-
-### Clear Gradle Cache
-
-If you need to, on Linux/Unix systems, you can delete all the existing artifacts (artifacts and metadata) Gradle has downloaded using:
-
-```bash
-# Only do this when absolutely necessary
-rm -rf $HOME/.gradle/caches/
-```
-
-Same strategy applies to Windows too, provided you switch `$HOME` to its equivalent in the above command.
-
-# Deployment
-
-- Create a keystore file `thekeystore` under `/etc/cas`. Use the password `changeit` for both the keystore and the key/certificate entries. This can either be done using the JDK's `keytool` utility or via the following command:
-
-```bash
-./gradlew[.bat] createKeystore
-```
-
-- Ensure the keystore is loaded up with keys and certificates of the server.
-
-On a successful deployment via the following methods, CAS will be available at:
-
-* `https://cas.server.name:8443/cas`
-
-## Executable WAR
-
-Run the CAS web application as an executable WAR:
-
-```bash
-./gradlew[.bat] run
-```
-
-Debug the CAS web application as an executable WAR:
-
-```bash
-./gradlew[.bat] debug
-```
-
-Run the CAS web application as a *standalone* executable WAR:
-
-```bash
-./gradlew[.bat] clean executable
-```
-
-## External
-
-Deploy the binary web application file `cas.war` after a successful build to a servlet container of choice.
-
-## Docker
-
-The following strategies outline how to build and deploy CAS Docker images.
-
-### Jib
-
-The overlay embraces the [Jib Gradle Plugin](https://github.com/GoogleContainerTools/jib) to provide easy-to-use out-of-the-box tooling for building CAS docker images. Jib is an open-source Java containerizer from Google that lets Java developers build containers using the tools they know. It is a container image builder that handles all the steps of packaging your application into a container image. It does not require you to write a Dockerfile or have Docker installed, and it is directly integrated into the overlay.
-
-```bash
-./gradlew build jibDockerBuild
-```
-
-### Dockerfile
-
-You can also use the native Docker tooling and the provided `Dockerfile` to build and run CAS.
-
-```bash
-chmod +x *.sh
-./docker-build.sh
-./docker-run.sh
-```
diff --git a/core-java-modules/core-java-14/README.md b/core-java-modules/core-java-14/README.md
index 0e8278c4f6..13bb468b30 100644
--- a/core-java-modules/core-java-14/README.md
+++ b/core-java-modules/core-java-14/README.md
@@ -7,3 +7,4 @@ This module contains articles about Java 14.
- [Guide to the @Serial Annotation in Java 14](https://www.baeldung.com/java-14-serial-annotation)
- [Java Text Blocks](https://www.baeldung.com/java-text-blocks)
- [Pattern Matching for instanceof in Java 14](https://www.baeldung.com/java-pattern-matching-instanceof)
+- [Helpful NullPointerExceptions in Java 14](https://www.baeldung.com/java-14-nullpointerexception)
diff --git a/core-java-modules/core-java-8-2/README.md b/core-java-modules/core-java-8-2/README.md
index 961941aac7..c1c09d2192 100644
--- a/core-java-modules/core-java-8-2/README.md
+++ b/core-java-modules/core-java-8-2/README.md
@@ -4,7 +4,6 @@ This module contains articles about Java 8 core features
### Relevant Articles:
-- [How to Delay Code Execution in Java](https://www.baeldung.com/java-delay-code-execution)
- [Run a Java Application from the Command Line](https://www.baeldung.com/java-run-jar-with-arguments)
- [Java 8 Stream skip() vs limit()](https://www.baeldung.com/java-stream-skip-vs-limit)
- [Guide to Java BiFunction Interface](https://www.baeldung.com/java-bifunction-interface)
diff --git a/core-java-modules/core-java-collections-2/README.md b/core-java-modules/core-java-collections-2/README.md
index de5daddb38..e5f6126811 100644
--- a/core-java-modules/core-java-collections-2/README.md
+++ b/core-java-modules/core-java-collections-2/README.md
@@ -12,4 +12,3 @@
- [Sorting in Java](https://www.baeldung.com/java-sorting)
- [Getting the Size of an Iterable in Java](https://www.baeldung.com/java-iterable-size)
- [Java Null-Safe Streams from Collections](https://www.baeldung.com/java-null-safe-streams-from-collections)
-- [Operating on and Removing an Item from Stream](https://www.baeldung.com/java-use-remove-item-stream)
diff --git a/core-java-modules/core-java-collections-maps/README.md b/core-java-modules/core-java-collections-maps/README.md
index 828f8992e1..15cb32fbe8 100644
--- a/core-java-modules/core-java-collections-maps/README.md
+++ b/core-java-modules/core-java-collections-maps/README.md
@@ -4,7 +4,6 @@ This module contains articles about Map data structures in Java.
### Relevant Articles:
- [Guide to the Guava BiMap](https://www.baeldung.com/guava-bimap)
-- [A Guide to Java HashMap](https://www.baeldung.com/java-hashmap)
- [A Guide to LinkedHashMap in Java](https://www.baeldung.com/java-linked-hashmap)
- [A Guide to TreeMap in Java](https://www.baeldung.com/java-treemap)
- [How to Store Duplicate Keys in a Map in Java?](https://www.baeldung.com/java-map-duplicate-keys)
diff --git a/core-java-modules/core-java-collections/README.md b/core-java-modules/core-java-collections/README.md
index 340c2b286e..12e3c5ac17 100644
--- a/core-java-modules/core-java-collections/README.md
+++ b/core-java-modules/core-java-collections/README.md
@@ -3,7 +3,6 @@
This module contains articles about Java collections
### Relevant Articles:
-- [Collect a Java Stream to an Immutable Collection](https://www.baeldung.com/java-stream-immutable-collection)
- [Introduction to the Java ArrayDeque](https://www.baeldung.com/java-array-deque)
- [An Introduction to Java.util.Hashtable Class](https://www.baeldung.com/java-hash-table)
- [Thread Safe LIFO Data Structure Implementations](https://www.baeldung.com/java-lifo-thread-safe)
@@ -13,4 +12,4 @@ This module contains articles about Java collections
- [Defining a Char Stack in Java](https://www.baeldung.com/java-char-stack)
- [Guide to the Java Queue Interface](https://www.baeldung.com/java-queue)
- [An Introduction to Synchronized Java Collections](https://www.baeldung.com/java-synchronized-collections)
-- [[More -->]](/core-java-modules/core-java-collections-2)
\ No newline at end of file
+- [[More -->]](/core-java-modules/core-java-collections-2)
diff --git a/core-java-modules/core-java-concurrency-advanced-3/README.md b/core-java-modules/core-java-concurrency-advanced-3/README.md
index 2c554e948b..b11cde5158 100644
--- a/core-java-modules/core-java-concurrency-advanced-3/README.md
+++ b/core-java-modules/core-java-concurrency-advanced-3/README.md
@@ -10,4 +10,5 @@ This module contains articles about advanced topics about multithreading with co
- [Guide to RejectedExecutionHandler](https://www.baeldung.com/java-rejectedexecutionhandler)
- [Guide to Work Stealing in Java](https://www.baeldung.com/java-work-stealing)
- [Asynchronous Programming in Java](https://www.baeldung.com/java-asynchronous-programming)
+- [Java Thread Deadlock and Livelock](https://www.baeldung.com/java-deadlock-livelock)
- [[<-- previous]](/core-java-modules/core-java-concurrency-advanced-2)
diff --git a/core-java-modules/core-java-concurrency-basic-2/README.md b/core-java-modules/core-java-concurrency-basic-2/README.md
index e3f7a94e14..c7143baf36 100644
--- a/core-java-modules/core-java-concurrency-basic-2/README.md
+++ b/core-java-modules/core-java-concurrency-basic-2/README.md
@@ -8,4 +8,5 @@ This module contains articles about basic Java concurrency
- [Difference Between Wait and Sleep in Java](https://www.baeldung.com/java-wait-and-sleep)
- [Guide to the Synchronized Keyword in Java](https://www.baeldung.com/java-synchronized)
- [Life Cycle of a Thread in Java](https://www.baeldung.com/java-thread-lifecycle)
-- [[<-- Prev]](/core-java-modules/core-java-concurrency-basic)
\ No newline at end of file
+- [Guide to AtomicMarkableReference](https://www.baeldung.com/java-atomicmarkablereference)
+- [[<-- Prev]](/core-java-modules/core-java-concurrency-basic)
diff --git a/core-java-modules/core-java-concurrency-collections-2/README.md b/core-java-modules/core-java-concurrency-collections-2/README.md
new file mode 100644
index 0000000000..91da6c623c
--- /dev/null
+++ b/core-java-modules/core-java-concurrency-collections-2/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles:
+
+- [Introduction to Lock Striping](https://www.baeldung.com/java-lock-stripping)
diff --git a/core-java-modules/core-java-date-operations-2/README.md b/core-java-modules/core-java-date-operations-2/README.md
index 728162ca1a..19c7b98d30 100644
--- a/core-java-modules/core-java-date-operations-2/README.md
+++ b/core-java-modules/core-java-date-operations-2/README.md
@@ -7,4 +7,5 @@ This module contains articles about date operations in Java.
- [Checking If Two Java Dates Are on the Same Day](https://www.baeldung.com/java-check-two-dates-on-same-day)
- [Converting Java Date to OffsetDateTime](https://www.baeldung.com/java-convert-date-to-offsetdatetime)
- [How to Set the JVM Time Zone](https://www.baeldung.com/java-jvm-time-zone)
+- [How to determine day of week by passing specific date in Java?](https://www.baeldung.com/java-get-day-of-week)
- [[<-- Prev]](/core-java-modules/core-java-date-operations-1)
diff --git a/core-java-modules/core-java-io-2/README.md b/core-java-modules/core-java-io-2/README.md
index 62461be0ff..84cabc5992 100644
--- a/core-java-modules/core-java-io-2/README.md
+++ b/core-java-modules/core-java-io-2/README.md
@@ -12,4 +12,5 @@ This module contains articles about core Java input and output (IO)
- [Java – Append Data to a File](https://www.baeldung.com/java-append-to-file)
- [How to Copy a File with Java](https://www.baeldung.com/java-copy-file)
- [Create a Directory in Java](https://www.baeldung.com/java-create-directory)
+- [Java IO vs NIO](https://www.baeldung.com/java-io-vs-nio)
- [[<-- Prev]](/core-java-modules/core-java-io)
diff --git a/core-java-modules/core-java-lang-2/README.md b/core-java-modules/core-java-lang-2/README.md
index 65d40c6a26..3ade982397 100644
--- a/core-java-modules/core-java-lang-2/README.md
+++ b/core-java-modules/core-java-lang-2/README.md
@@ -10,4 +10,5 @@ This module contains articles about core features in the Java language
- [How to Return Multiple Values From a Java Method](https://www.baeldung.com/java-method-return-multiple-values)
- [Guide to the Java finally Keyword](https://www.baeldung.com/java-finally-keyword)
- [The Java Headless Mode](https://www.baeldung.com/java-headless-mode)
+- [Comparing Long Values in Java](https://www.baeldung.com/java-compare-long-values)
- [[<-- Prev]](/core-java-modules/core-java-lang)
diff --git a/core-java-modules/core-java-regex/README.md b/core-java-modules/core-java-regex/README.md
index 21cd7a95a3..6fdea9f2ca 100644
--- a/core-java-modules/core-java-regex/README.md
+++ b/core-java-modules/core-java-regex/README.md
@@ -9,3 +9,4 @@
- [Pre-compile Regex Patterns Into Pattern Objects](https://www.baeldung.com/java-regex-pre-compile)
- [Difference Between Java Matcher find() and matches()](https://www.baeldung.com/java-matcher-find-vs-matches)
- [How to Use Regular Expressions to Replace Tokens in Strings](https://www.baeldung.com/java-regex-token-replacement)
+- [Regular Expressions \s and \s+ in Java](https://www.baeldung.com/java-regex-s-splus)
diff --git a/core-java-modules/core-java-security-2/README.md b/core-java-modules/core-java-security-2/README.md
index 2eb21fb77e..24a821bd4d 100644
--- a/core-java-modules/core-java-security-2/README.md
+++ b/core-java-modules/core-java-security-2/README.md
@@ -8,4 +8,5 @@ This module contains articles about core Java Security
- [MD5 Hashing in Java](http://www.baeldung.com/java-md5)
- [Hashing a Password in Java](https://www.baeldung.com/java-password-hashing)
- [SHA-256 and SHA3-256 Hashing in Java](https://www.baeldung.com/sha-256-hashing-java)
+- [Checksums in Java](https://www.baeldung.com/java-checksums)
- More articles: [[<-- prev]](/core-java-modules/core-java-security)
diff --git a/core-java-modules/core-java-streams-3/README.md b/core-java-modules/core-java-streams-3/README.md
index a739245399..05c4b99900 100644
--- a/core-java-modules/core-java-streams-3/README.md
+++ b/core-java-modules/core-java-streams-3/README.md
@@ -9,4 +9,5 @@ This module contains articles about the Stream API in Java.
- [Guide to Java 8’s Collectors](https://www.baeldung.com/java-8-collectors)
- [Primitive Type Streams in Java 8](https://www.baeldung.com/java-8-primitive-streams)
- [Debugging Java 8 Streams with IntelliJ](https://www.baeldung.com/intellij-debugging-java-streams)
+- [Add BigDecimals using the Stream API](https://www.baeldung.com/java-stream-add-bigdecimals)
- More articles: [[<-- prev>]](/../core-java-streams-2)
diff --git a/core-java-modules/core-java-string-operations/README.md b/core-java-modules/core-java-string-operations/README.md
index 18a2649a6a..c40e56bc46 100644
--- a/core-java-modules/core-java-string-operations/README.md
+++ b/core-java-modules/core-java-string-operations/README.md
@@ -13,4 +13,5 @@ This module contains articles about string operations.
- [Adding a Newline Character to a String in Java](https://www.baeldung.com/java-string-newline)
- [Check If a String Contains a Substring](https://www.baeldung.com/java-string-contains-substring)
- [Java Base64 Encoding and Decoding](https://www.baeldung.com/java-base64-encode-and-decode)
+- [Java Convert PDF to Base64](https://www.baeldung.com/java-convert-pdf-to-base64)
- More articles: [[next -->]](../core-java-string-operations-2)
diff --git a/core-java-modules/core-java-strings/README.md b/core-java-modules/core-java-strings/README.md
index 4a418db29f..5daae8394a 100644
--- a/core-java-modules/core-java-strings/README.md
+++ b/core-java-modules/core-java-strings/README.md
@@ -12,3 +12,4 @@ This module contains articles about strings in Java.
- [Java String Interview Questions and Answers](https://www.baeldung.com/java-string-interview-questions)
- [Java Multi-line String](https://www.baeldung.com/java-multiline-string)
- [Guide to Java String Pool](https://www.baeldung.com/java-string-pool)
+- [Fixing “constant string too long” Build Error](https://www.baeldung.com/java-constant-string-too-long-error)
diff --git a/core-kotlin-modules/core-kotlin-collections/README.md b/core-kotlin-modules/core-kotlin-collections/README.md
index bbea5869af..f0da2b4cfd 100644
--- a/core-kotlin-modules/core-kotlin-collections/README.md
+++ b/core-kotlin-modules/core-kotlin-collections/README.md
@@ -8,3 +8,4 @@ This module contains articles about core Kotlin collections.
- [Overview of Kotlin Collections API](https://www.baeldung.com/kotlin-collections-api)
- [Converting a List to Map in Kotlin](https://www.baeldung.com/kotlin-list-to-map)
- [Filtering Kotlin Collections](https://www.baeldung.com/kotlin-filter-collection)
+- [Collection Transformations in Kotlin](https://www.baeldung.com/kotlin-collection-transformations)
diff --git a/core-kotlin-modules/core-kotlin/README.md b/core-kotlin-modules/core-kotlin/README.md
index 90caccf5c8..151da607ac 100644
--- a/core-kotlin-modules/core-kotlin/README.md
+++ b/core-kotlin-modules/core-kotlin/README.md
@@ -3,7 +3,7 @@
This module contains articles about Kotlin core features.
### Relevant articles:
-- [Introduction to the Kotlin Language](https://www.baeldung.com/kotlin-intro)
+- [Introduction to the Kotlin Language](https://www.baeldung.com/kotlin/tutorial)
- [Kotlin Java Interoperability](https://www.baeldung.com/kotlin-java-interoperability)
- [Get a Random Number in Kotlin](https://www.baeldung.com/kotlin-random-number)
- [Create a Java and Kotlin Project with Maven](https://www.baeldung.com/kotlin-maven-java-project)
diff --git a/core-scala/README.md b/core-scala/README.md
new file mode 100644
index 0000000000..72b583c22b
--- /dev/null
+++ b/core-scala/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles:
+
+- [Pattern Matching in Scala](https://www.baeldung.com/scala/pattern-matching)
diff --git a/guava-collections-map/README.md b/guava-collections-map/README.md
index b3ec5e2157..4f8743dcfb 100644
--- a/guava-collections-map/README.md
+++ b/guava-collections-map/README.md
@@ -9,4 +9,5 @@ This module contains articles about map collections in Guava
- [Guide to Guava Multimap](https://www.baeldung.com/guava-multimap)
- [Guide to Guava RangeMap](https://www.baeldung.com/guava-rangemap)
- [Initialize a HashMap in Java](https://www.baeldung.com/java-initialize-hashmap)
-- [Guide to Guava ClassToInstanceMap](https://www.baeldung.com/guava-class-to-instance-map)
\ No newline at end of file
+- [Guide to Guava ClassToInstanceMap](https://www.baeldung.com/guava-class-to-instance-map)
+- [Using Guava’s MapMaker](https://www.baeldung.com/guava-mapmaker)
diff --git a/guava/README.md b/guava/README.md
index c67a3604ea..71f76c1360 100644
--- a/guava/README.md
+++ b/guava/README.md
@@ -12,4 +12,4 @@ This module contains articles a Google Guava
- [Guide to Mathematical Utilities in Guava](https://www.baeldung.com/guava-math)
- [Bloom Filter in Java using Guava](https://www.baeldung.com/guava-bloom-filter)
- [Quick Guide to the Guava RateLimiter](https://www.baeldung.com/guava-rate-limiter)
-
+- [Introduction to Guava Throwables](https://www.baeldung.com/guava-throwables)
diff --git a/java-collections-maps-3/README.md b/java-collections-maps-3/README.md
new file mode 100644
index 0000000000..ed68eb00a0
--- /dev/null
+++ b/java-collections-maps-3/README.md
@@ -0,0 +1,8 @@
+## Java Collections Cookbooks and Examples
+
+This module contains articles about Map data structures in Java.
+
+### Relevant Articles:
+
+- More articles: [[<-- prev>]](/../java-collections-maps)
+- More articles: [[<-- prev>]](/../java-collections-maps-2)
diff --git a/java-collections-maps-3/pom.xml b/java-collections-maps-3/pom.xml
new file mode 100644
index 0000000000..3888623a7f
--- /dev/null
+++ b/java-collections-maps-3/pom.xml
@@ -0,0 +1,43 @@
+
+
+
+ com.baeldung
+ parent-java
+ 0.0.1-SNAPSHOT
+ ../parent-java
+
+
+ 4.0.0
+ java-collections-maps-3
+ 0.1.0-SNAPSHOT
+ java-collections-maps-3
+ jar
+
+
+
+ org.springframework
+ spring-core
+ ${spring.version}
+ test
+
+
+ org.assertj
+ assertj-core
+ ${assertj.version}
+ test
+
+
+ org.apache.commons
+ commons-collections4
+ ${commons-collections4.version}
+
+
+
+
+ 4.1
+ 3.6.1
+ 5.2.5.RELEASE
+
+
diff --git a/java-collections-maps-3/src/test/java/com/baeldung/map/caseinsensitivekeys/CaseInsensitiveMapUnitTest.java b/java-collections-maps-3/src/test/java/com/baeldung/map/caseinsensitivekeys/CaseInsensitiveMapUnitTest.java
new file mode 100644
index 0000000000..833807c692
--- /dev/null
+++ b/java-collections-maps-3/src/test/java/com/baeldung/map/caseinsensitivekeys/CaseInsensitiveMapUnitTest.java
@@ -0,0 +1,94 @@
+package com.baeldung.map.caseinsensitivekeys;
+
+import org.apache.commons.collections4.map.CaseInsensitiveMap;
+import org.junit.Test;
+import org.springframework.util.LinkedCaseInsensitiveMap;
+import java.util.Map;
+import java.util.TreeMap;
+import static org.junit.Assert.*;
+
+public class CaseInsensitiveMapUnitTest {
+ @Test
+ public void givenCaseInsensitiveTreeMap_whenTwoEntriesAdded_thenSizeIsOne(){
+ Map treeMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+ treeMap.put("abc", 1);
+ treeMap.put("ABC", 2);
+
+ assertEquals(1, treeMap.size());
+ }
+
+ @Test
+ public void givenCommonsCaseInsensitiveMap_whenTwoEntriesAdded_thenSizeIsOne(){
+ Map commonsHashMap = new CaseInsensitiveMap<>();
+ commonsHashMap.put("abc", 1);
+ commonsHashMap.put("ABC", 2);
+
+ assertEquals(1, commonsHashMap.size());
+ }
+
+ @Test
+ public void givenLinkedCaseInsensitiveMap_whenTwoEntriesAdded_thenSizeIsOne(){
+ Map linkedHashMap = new LinkedCaseInsensitiveMap<>();
+ linkedHashMap.put("abc", 1);
+ linkedHashMap.put("ABC", 2);
+
+ assertEquals(1, linkedHashMap.size());
+ }
+
+ @Test
+ public void givenCaseInsensitiveTreeMap_whenSameEntryAdded_thenValueUpdated(){
+ Map treeMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+ treeMap.put("abc", 1);
+ treeMap.put("ABC", 2);
+
+ assertEquals(2, treeMap.get("aBc").intValue());
+ assertEquals(2, treeMap.get("ABc").intValue());
+ }
+
+ @Test
+ public void givenCommonsCaseInsensitiveMap_whenSameEntryAdded_thenValueUpdated(){
+ Map commonsHashMap = new CaseInsensitiveMap<>();
+ commonsHashMap.put("abc", 1);
+ commonsHashMap.put("ABC", 2);
+
+ assertEquals(2, commonsHashMap.get("aBc").intValue());
+ assertEquals(2, commonsHashMap.get("ABc").intValue());
+ }
+
+ @Test
+ public void givenLinkedCaseInsensitiveMap_whenSameEntryAdded_thenValueUpdated(){
+ Map linkedHashMap = new LinkedCaseInsensitiveMap<>();
+ linkedHashMap.put("abc", 1);
+ linkedHashMap.put("ABC", 2);
+
+ assertEquals(2, linkedHashMap.get("aBc").intValue());
+ assertEquals(2, linkedHashMap.get("ABc").intValue());
+ }
+
+ @Test
+ public void givenCaseInsensitiveTreeMap_whenEntryRemoved_thenSizeIsZero(){
+ Map treeMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+ treeMap.put("abc", 3);
+ treeMap.remove("aBC");
+
+ assertEquals(0, treeMap.size());
+ }
+
+ @Test
+ public void givenCommonsCaseInsensitiveMap_whenEntryRemoved_thenSizeIsZero(){
+ Map commonsHashMap = new CaseInsensitiveMap<>();
+ commonsHashMap.put("abc", 3);
+ commonsHashMap.remove("aBC");
+
+ assertEquals(0, commonsHashMap.size());
+ }
+
+ @Test
+ public void givenLinkedCaseInsensitiveMap_whenEntryRemoved_thenSizeIsZero(){
+ Map linkedHashMap = new LinkedCaseInsensitiveMap<>();
+ linkedHashMap.put("abc", 3);
+ linkedHashMap.remove("aBC");
+
+ assertEquals(0, linkedHashMap.size());
+ }
+}
diff --git a/java-numbers-3/README.md b/java-numbers-3/README.md
index 598acfb927..f818bdb675 100644
--- a/java-numbers-3/README.md
+++ b/java-numbers-3/README.md
@@ -10,4 +10,5 @@ This module contains articles about numbers in Java.
- [Generating Random Numbers in a Range in Java](https://www.baeldung.com/java-generating-random-numbers-in-range)
- [Listing Numbers Within a Range in Java](https://www.baeldung.com/java-listing-numbers-within-a-range)
- [Fibonacci Series in Java](https://www.baeldung.com/java-fibonacci)
+- [Guide to the Number Class in Java](https://www.baeldung.com/java-number-class)
- More articles: [[<-- prev]](/java-numbers-2)
diff --git a/java-numbers/README.md b/java-numbers/README.md
index 8f53006b38..f4b76c3c98 100644
--- a/java-numbers/README.md
+++ b/java-numbers/README.md
@@ -12,4 +12,5 @@ This module contains articles about numbers in Java.
- [Calculating the nth Root in Java](https://www.baeldung.com/java-nth-root)
- [Convert Double to String, Removing Decimal Places](https://www.baeldung.com/java-double-to-string)
- [Changing the Order in a Sum Operation Can Produce Different Results?](https://www.baeldung.com/java-floating-point-sum-order)
+- [Using Math.sin with Degrees](https://www.baeldung.com/java-math-sin-degrees)
- More articles: [[next -->]](/../java-numbers-2)
diff --git a/jhipster-5/bookstore-monolith/pom.xml b/jhipster-5/bookstore-monolith/pom.xml
index 5eaf761921..233765e0f3 100644
--- a/jhipster-5/bookstore-monolith/pom.xml
+++ b/jhipster-5/bookstore-monolith/pom.xml
@@ -7,7 +7,7 @@
0.0.1-SNAPSHOT
war
Bookstore
-
+
jhipster-5
com.baeldung.jhipster
@@ -982,7 +982,7 @@
com.github.eirslett
- frontend-maven-plugin
+ frontend-maven-plugin
${frontend-maven-plugin.version}
install-node-and-npm
diff --git a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/mapper/UserMapperUnitTest.java b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/mapper/UserMapperIntegrationTest.java
similarity index 99%
rename from jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/mapper/UserMapperUnitTest.java
rename to jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/mapper/UserMapperIntegrationTest.java
index cd6a326c06..cd49135d63 100644
--- a/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/mapper/UserMapperUnitTest.java
+++ b/jhipster-5/bookstore-monolith/src/test/java/com/baeldung/jhipster5/service/mapper/UserMapperIntegrationTest.java
@@ -26,7 +26,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = BookstoreApp.class)
-public class UserMapperUnitTest {
+public class UserMapperIntegrationTest {
private static final String DEFAULT_LOGIN = "johndoe";
diff --git a/libraries-3/README.md b/libraries-3/README.md
index f3c3375098..ec433960ef 100644
--- a/libraries-3/README.md
+++ b/libraries-3/README.md
@@ -15,4 +15,5 @@ Remember, for advanced libraries like [Jackson](/jackson) and [JUnit](/testing-m
- [Introduction to the jcabi-aspects AOP Annotations Library](https://www.baeldung.com/java-jcabi-aspects)
- [Introduction to Takes](https://www.baeldung.com/java-takes)
- [Using NullAway to Avoid NullPointerExceptions](https://www.baeldung.com/java-nullaway)
-
+- [Introduction to Alibaba Arthas](https://www.baeldung.com/java-alibaba-arthas-intro)
+- [Quick Guide to Spring Cloud Circuit Breaker](https://www.baeldung.com/spring-cloud-circuit-breaker)
diff --git a/libraries-concurrency/README.md b/libraries-concurrency/README.md
new file mode 100644
index 0000000000..d1ffe81fa8
--- /dev/null
+++ b/libraries-concurrency/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles:
+
+- [Intro to Coroutines with Quasar](https://www.baeldung.com/java-quasar-coroutines)
diff --git a/linux-bash/command-line-arguments/src/main/bash/README.md b/linux-bash/command-line-arguments/src/main/bash/README.md
new file mode 100644
index 0000000000..27d89fff99
--- /dev/null
+++ b/linux-bash/command-line-arguments/src/main/bash/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles:
+
+- [How to Use Command Line Arguments in a Bash Script](https://www.baeldung.com/linux/use-command-line-arguments-in-bash-script)
diff --git a/linux-bash/functions/src/main/bash/README.md b/linux-bash/functions/src/main/bash/README.md
new file mode 100644
index 0000000000..5fb6958b9d
--- /dev/null
+++ b/linux-bash/functions/src/main/bash/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles
+
+- [Bash Functions in Linux](https://www.baeldung.com/linux/bash-functions)
diff --git a/linux-bash/read/README.md b/linux-bash/read/README.md
new file mode 100644
index 0000000000..56c1dd5b24
--- /dev/null
+++ b/linux-bash/read/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles:
+
+- [Guide to the Linux read Command](https://www.baeldung.com/linux/read-command)
diff --git a/linux-bash/text/README.md b/linux-bash/text/README.md
index de99c1962a..20df2a33ec 100644
--- a/linux-bash/text/README.md
+++ b/linux-bash/text/README.md
@@ -1,3 +1,4 @@
### Relevant Articles:
- [Linux Commands – Remove All Text After X](https://www.baeldung.com/linux/tr-manipulate-strings)
+- [Linux Commands for Appending Multiple Lines to a File](https://www.baeldung.com/linux/appending-multiple-lines-to-file2)
diff --git a/logging-modules/log-mdc/README.md b/logging-modules/log-mdc/README.md
index b676d3ba76..0d516619ef 100644
--- a/logging-modules/log-mdc/README.md
+++ b/logging-modules/log-mdc/README.md
@@ -1,7 +1,7 @@
### Relevant Articles:
- TBD
- [Improved Java Logging with Mapped Diagnostic Context (MDC)](https://www.baeldung.com/mdc-in-log4j-2-logback)
-- [Java Logging with Nested Diagnostic Context (NDC)](https:www.baeldung.com/java-logging-ndc-log4j)
+- [Java Logging with Nested Diagnostic Context (NDC)](https://www.baeldung.com/java-logging-ndc-log4j)
- [Drools Using Rules from Excel Files](https://www.baeldung.com/drools-excel)
### References
diff --git a/lombok/src/main/README.md b/lombok/src/main/README.md
new file mode 100644
index 0000000000..4092d8ce99
--- /dev/null
+++ b/lombok/src/main/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles:
+
+- [Guide to the Linux wc Command](https://www.baeldung.com/linux/wc-command)
diff --git a/persistence-modules/hibernate-jpa/README.md b/persistence-modules/hibernate-jpa/README.md
index d0a253f028..fb48f975bc 100644
--- a/persistence-modules/hibernate-jpa/README.md
+++ b/persistence-modules/hibernate-jpa/README.md
@@ -13,3 +13,4 @@ This module contains articles specific to use of Hibernate as a JPA implementati
- [Enabling Transaction Locks in Spring Data JPA](https://www.baeldung.com/java-jpa-transaction-locks)
- [TransactionRequiredException Error](https://www.baeldung.com/jpa-transaction-required-exception)
- [JPA/Hibernate Persistence Context](https://www.baeldung.com/jpa-hibernate-persistence-context)
+- [Quick Guide to EntityManager#getReference()](https://www.baeldung.com/jpa-entity-manager-get-reference)
diff --git a/persistence-modules/java-cassandra/pom.xml b/persistence-modules/java-cassandra/pom.xml
index 54879fb321..091efaeff4 100644
--- a/persistence-modules/java-cassandra/pom.xml
+++ b/persistence-modules/java-cassandra/pom.xml
@@ -18,6 +18,12 @@
cassandra-driver-core
${cassandra-driver-core.version}
true
+
+
+ com.google.guava
+ guava
+
+
diff --git a/persistence-modules/java-cassandra/src/test/resources/cassandra.yaml b/persistence-modules/java-cassandra/src/test/resources/cassandra.yaml
new file mode 100644
index 0000000000..59687444d0
--- /dev/null
+++ b/persistence-modules/java-cassandra/src/test/resources/cassandra.yaml
@@ -0,0 +1,51 @@
+cluster_name: 'Test Cluster'
+hinted_handoff_enabled: true
+max_hint_window_in_ms: 10800000
+hinted_handoff_throttle_in_kb: 1024
+max_hints_delivery_threads: 2
+hints_directory: target/embeddedCassandra/hints
+authenticator: AllowAllAuthenticator
+authorizer: AllowAllAuthorizer
+permissions_validity_in_ms: 2000
+partitioner: RandomPartitioner
+data_file_directories:
+ - target/embeddedCassandra/data
+commitlog_directory: target/embeddedCassandra/commitlog
+cdc_raw_directory: target/embeddedCassandra/cdc
+disk_failure_policy: stop
+key_cache_size_in_mb:
+key_cache_save_period: 14400
+row_cache_size_in_mb: 0
+row_cache_save_period: 0
+saved_caches_directory: target/embeddedCassandra/saved_caches
+commitlog_sync: periodic
+commitlog_sync_period_in_ms: 10000
+commitlog_segment_size_in_mb: 32
+concurrent_reads: 32
+concurrent_writes: 32
+trickle_fsync: false
+trickle_fsync_interval_in_kb: 10240
+thrift_framed_transport_size_in_mb: 15
+thrift_max_message_length_in_mb: 16
+incremental_backups: false
+snapshot_before_compaction: false
+auto_snapshot: false
+column_index_size_in_kb: 64
+compaction_throughput_mb_per_sec: 16
+read_request_timeout_in_ms: 5000
+range_request_timeout_in_ms: 10000
+write_request_timeout_in_ms: 2000
+cas_contention_timeout_in_ms: 1000
+truncate_request_timeout_in_ms: 60000
+request_timeout_in_ms: 10000
+cross_node_timeout: false
+endpoint_snitch: SimpleSnitch
+dynamic_snitch_update_interval_in_ms: 100
+dynamic_snitch_reset_interval_in_ms: 600000
+dynamic_snitch_badness_threshold: 0.1
+request_scheduler: org.apache.cassandra.scheduler.NoScheduler
+index_interval: 128
+seed_provider:
+ - class_name: org.apache.cassandra.locator.SimpleSeedProvider
+ parameters:
+ - seeds: "127.0.0.1"
diff --git a/persistence-modules/spring-boot-persistence-h2/README.md b/persistence-modules/spring-boot-persistence-h2/README.md
index a0f9c67a33..d11ec1f409 100644
--- a/persistence-modules/spring-boot-persistence-h2/README.md
+++ b/persistence-modules/spring-boot-persistence-h2/README.md
@@ -1,4 +1,5 @@
### Relevant Articles:
- [Access the Same In-Memory H2 Database in Multiple Spring Boot Applications](https://www.baeldung.com/spring-boot-access-h2-database-multiple-apps)
- [Spring Boot With H2 Database](https://www.baeldung.com/spring-boot-h2-database)
-- [Hibernate @NotNull vs @Column(nullable = false)](https://www.baeldung.com/hibernate-notnull-vs-nullable)
\ No newline at end of file
+- [Hibernate @NotNull vs @Column(nullable = false)](https://www.baeldung.com/hibernate-notnull-vs-nullable)
+- [Quick Guide to Hibernate enable_lazy_load_no_trans Property](https://www.baeldung.com/hibernate-lazy-loading-workaround)
diff --git a/persistence-modules/spring-data-jpa-4/create.sql b/persistence-modules/spring-data-jpa-4/create.sql
new file mode 100644
index 0000000000..1bbe1640a7
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/create.sql
@@ -0,0 +1,2 @@
+create table PERSON (ID int8 not null, FIRST_NAME varchar(255), LAST_NAME varchar(255), primary key (ID))
+create table person (id int8 not null, first_name varchar(255), last_name varchar(255), primary key (id))
diff --git a/persistence-modules/spring-data-jpa-4/pom.xml b/persistence-modules/spring-data-jpa-4/pom.xml
index 8a476012c7..71fc21527f 100644
--- a/persistence-modules/spring-data-jpa-4/pom.xml
+++ b/persistence-modules/spring-data-jpa-4/pom.xml
@@ -33,6 +33,11 @@
mysql-connector-java
+
+ org.postgresql
+ postgresql
+
+
com.h2database
h2
diff --git a/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/Person.java b/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/Person.java
new file mode 100644
index 0000000000..cfb6e67c2c
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/Person.java
@@ -0,0 +1,35 @@
+package com.baeldung.namingstrategy;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+@Entity
+public class Person {
+ @Id
+ private Long id;
+
+ private String firstName;
+
+ private String lastName;
+
+ public Person() {}
+
+ public Person(Long id, String firstName, String lastName) {
+ this.id = id;
+ this.firstName = firstName;
+ this.lastName = lastName;
+ }
+
+ public Long id() {
+ return id;
+ }
+
+ public String firstName() {
+ return firstName;
+ }
+
+ public String lastName() {
+ return lastName;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/PersonRepository.java b/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/PersonRepository.java
new file mode 100644
index 0000000000..3c7c25bbcb
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/PersonRepository.java
@@ -0,0 +1,6 @@
+package com.baeldung.namingstrategy;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface PersonRepository extends JpaRepository {
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategy.java b/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategy.java
new file mode 100644
index 0000000000..16b01e50e3
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategy.java
@@ -0,0 +1,12 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.boot.model.naming.Identifier;
+import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
+import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
+
+public class QuotedLowerCaseNamingStrategy extends SpringPhysicalNamingStrategy {
+ @Override
+ protected Identifier getIdentifier(String name, boolean quoted, JdbcEnvironment jdbcEnvironment) {
+ return new Identifier(name.toLowerCase(), true);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategy.java b/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategy.java
new file mode 100644
index 0000000000..3cb62aa5a2
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategy.java
@@ -0,0 +1,12 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.boot.model.naming.Identifier;
+import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
+import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
+
+public class QuotedUpperCaseNamingStrategy extends SpringPhysicalNamingStrategy {
+ @Override
+ protected Identifier getIdentifier(String name, boolean quoted, JdbcEnvironment jdbcEnvironment) {
+ return new Identifier(name.toUpperCase(), true);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/SpringDataJpaNamingConventionApplication.java b/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/SpringDataJpaNamingConventionApplication.java
new file mode 100644
index 0000000000..f223015db8
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/SpringDataJpaNamingConventionApplication.java
@@ -0,0 +1,7 @@
+package com.baeldung.namingstrategy;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SpringDataJpaNamingConventionApplication {
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategy.java b/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategy.java
new file mode 100644
index 0000000000..69e96aee27
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategy.java
@@ -0,0 +1,12 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.boot.model.naming.Identifier;
+import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
+import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
+
+public class UnquotedLowerCaseNamingStrategy extends SpringPhysicalNamingStrategy {
+ @Override
+ protected Identifier getIdentifier(String name, boolean quoted, JdbcEnvironment jdbcEnvironment) {
+ return new Identifier(name.toLowerCase(), false);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/UnquotedUpperCaseNamingStrategy.java b/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/UnquotedUpperCaseNamingStrategy.java
new file mode 100644
index 0000000000..cb87af10f4
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/main/java/com/baeldung/namingstrategy/UnquotedUpperCaseNamingStrategy.java
@@ -0,0 +1,12 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.boot.model.naming.Identifier;
+import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
+import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
+
+public class UnquotedUpperCaseNamingStrategy extends SpringPhysicalNamingStrategy {
+ @Override
+ protected Identifier getIdentifier(String name, boolean quoted, JdbcEnvironment jdbcEnvironment) {
+ return new Identifier(name.toUpperCase(), false);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategyH2IntegrationTest.java b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategyH2IntegrationTest.java
new file mode 100644
index 0000000000..71a4dbda3f
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategyH2IntegrationTest.java
@@ -0,0 +1,81 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("quoted-lower-case-naming-strategy.properties")
+class QuotedLowerCaseNamingStrategyH2IntegrationTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonUnquoted_thenException(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Unexpected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ @Test
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonQuotedUpperCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Expected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ @Test
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonQuotedLowerCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategyPostgresLiveTest.java b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategyPostgresLiveTest.java
new file mode 100644
index 0000000000..6b1c984600
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategyPostgresLiveTest.java
@@ -0,0 +1,85 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("quoted-lower-case-naming-strategy-on-postgres.properties")
+class QuotedLowerCaseNamingStrategyPostgresLiveTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonUnquoted_thenResult(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonQuotedUpperCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Expected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ @Test
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonQuotedLowerCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategyH2IntegrationTest.java b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategyH2IntegrationTest.java
new file mode 100644
index 0000000000..f819327a5c
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategyH2IntegrationTest.java
@@ -0,0 +1,85 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("quoted-upper-case-naming-strategy.properties")
+class QuotedUpperCaseNamingStrategyH2IntegrationTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonUnquoted_thenException(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonQuotedUpperCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonQuotedLowerCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Expected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategyPostgresLiveTest.java b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategyPostgresLiveTest.java
new file mode 100644
index 0000000000..bd23b81b4b
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategyPostgresLiveTest.java
@@ -0,0 +1,81 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("quoted-upper-case-naming-strategy-on-postgres.properties")
+class QuotedUpperCaseNamingStrategyPostgresLiveTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonUnquoted_thenResult(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Unexpected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ @Test
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonQuotedUpperCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonQuotedLowerCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Expected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/SpringPhysicalNamingStrategyH2IntegrationTest.java b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/SpringPhysicalNamingStrategyH2IntegrationTest.java
new file mode 100644
index 0000000000..1850fea173
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/SpringPhysicalNamingStrategyH2IntegrationTest.java
@@ -0,0 +1,85 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("spring-physical-naming-strategy.properties")
+class SpringPhysicalNamingStrategyH2IntegrationTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndSpringNamingStrategy_whenQueryPersonUnquoted_thenResult(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndSpringNamingStrategy_whenQueryPersonQuotedUpperCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Unexpected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndSpringNamingStrategy_whenQueryPersonQuotedLowerCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Unexpected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/SpringPhysicalNamingStrategyPostgresLiveTest.java b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/SpringPhysicalNamingStrategyPostgresLiveTest.java
new file mode 100644
index 0000000000..e26ebb148d
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/SpringPhysicalNamingStrategyPostgresLiveTest.java
@@ -0,0 +1,85 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("spring-physical-naming-strategy-on-postgres.properties")
+class SpringPhysicalNamingStrategyPostgresLiveTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndSpringNamingStrategy_whenQueryPersonUnquoted_thenResult(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndSpringNamingStrategy_whenQueryPersonQuotedUpperCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Expected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ @Test
+ void givenPeopleAndSpringNamingStrategy_whenQueryPersonQuotedLowerCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategyH2IntegrationTest.java b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategyH2IntegrationTest.java
new file mode 100644
index 0000000000..6311c42e93
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategyH2IntegrationTest.java
@@ -0,0 +1,86 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("unquoted-lower-case-naming-strategy.properties")
+class UnquotedLowerCaseNamingStrategyH2IntegrationTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonUnquoted_thenResult(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonQuotedUpperCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Unexpected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonQuotedLowerCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Unexpected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategyPostgresLiveTest.java b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategyPostgresLiveTest.java
new file mode 100644
index 0000000000..033a213cf5
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategyPostgresLiveTest.java
@@ -0,0 +1,85 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("unquoted-lower-case-naming-strategy-on-postgres.properties")
+class UnquotedLowerCaseNamingStrategyPostgresLiveTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonUnquoted_thenResult(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonQuotedUpperCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Expected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ @Test
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonQuotedLowerCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/UnquotedUpperCaseNamingStrategyH2IntegrationTest.java b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/UnquotedUpperCaseNamingStrategyH2IntegrationTest.java
new file mode 100644
index 0000000000..7af8001854
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/UnquotedUpperCaseNamingStrategyH2IntegrationTest.java
@@ -0,0 +1,85 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("unquoted-upper-case-naming-strategy.properties")
+class UnquotedUpperCaseNamingStrategyH2IntegrationTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonUnquoted_thenResult(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonQuotedUpperCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonQuotedLowerCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Expected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/UnquotedUpperCaseNamingStrategyPostgresLiveTest.java b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/UnquotedUpperCaseNamingStrategyPostgresLiveTest.java
new file mode 100644
index 0000000000..0151e7ece4
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/java/com/baeldung/namingstrategy/UnquotedUpperCaseNamingStrategyPostgresLiveTest.java
@@ -0,0 +1,85 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("unquoted-upper-case-naming-strategy-on-postgres.properties")
+class UnquotedUpperCaseNamingStrategyPostgresLiveTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonUnquoted_thenResult(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonQuotedUpperCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Unexpected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ @Test
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonQuotedLowerCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Unexpected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/quoted-lower-case-naming-strategy-on-postgres.properties b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/quoted-lower-case-naming-strategy-on-postgres.properties
new file mode 100644
index 0000000000..04b29de41f
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/quoted-lower-case-naming-strategy-on-postgres.properties
@@ -0,0 +1,9 @@
+spring.datasource.url=jdbc:postgresql://localhost:5432/quoted-lower-case-strategy
+spring.datasource.username=postgres
+spring.datasource.password=root
+
+spring.jpa.hibernate.ddl-auto=create-drop
+spring.jpa.hibernate.naming.physical-strategy=com.baeldung.namingstrategy.QuotedLowerCaseNamingStrategy
+#spring.jpa.properties.javax.persistence.schema-generation.create-source=metadata
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=upper-case-naming-strategy-ddl.sql
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/quoted-lower-case-naming-strategy.properties b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/quoted-lower-case-naming-strategy.properties
new file mode 100644
index 0000000000..6643c12c8a
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/quoted-lower-case-naming-strategy.properties
@@ -0,0 +1,9 @@
+spring.datasource.url=jdbc:h2:mem:quoted-lower-case-strategy
+spring.datasource.username=sa
+spring.datasource.password=
+
+spring.jpa.hibernate.ddl-auto=create-drop
+spring.jpa.hibernate.naming.physical-strategy=com.baeldung.namingstrategy.QuotedLowerCaseNamingStrategy
+#spring.jpa.properties.javax.persistence.schema-generation.create-source=metadata
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=upper-case-naming-strategy-ddl.sql
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/quoted-upper-case-naming-strategy-on-postgres.properties b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/quoted-upper-case-naming-strategy-on-postgres.properties
new file mode 100644
index 0000000000..36898d5b4f
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/quoted-upper-case-naming-strategy-on-postgres.properties
@@ -0,0 +1,9 @@
+spring.datasource.url=jdbc:postgresql://localhost:5432/quoted-upper-case-strategy
+spring.datasource.username=postgres
+spring.datasource.password=root
+
+spring.jpa.hibernate.ddl-auto=create-drop
+spring.jpa.hibernate.naming.physical-strategy=com.baeldung.namingstrategy.QuotedUpperCaseNamingStrategy
+#spring.jpa.properties.javax.persistence.schema-generation.create-source=metadata
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=upper-case-naming-strategy-ddl.sql
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/quoted-upper-case-naming-strategy.properties b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/quoted-upper-case-naming-strategy.properties
new file mode 100644
index 0000000000..6d56d58749
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/quoted-upper-case-naming-strategy.properties
@@ -0,0 +1,9 @@
+spring.datasource.url=jdbc:h2:mem:quoted-upper-case-strategy
+spring.datasource.username=sa
+spring.datasource.password=
+
+spring.jpa.hibernate.ddl-auto=create-drop
+spring.jpa.hibernate.naming.physical-strategy=com.baeldung.namingstrategy.QuotedUpperCaseNamingStrategy
+#spring.jpa.properties.javax.persistence.schema-generation.create-source=metadata
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=upper-case-naming-strategy-ddl.sql
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/spring-physical-naming-strategy-on-postgres.properties b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/spring-physical-naming-strategy-on-postgres.properties
new file mode 100644
index 0000000000..706b12b1b6
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/spring-physical-naming-strategy-on-postgres.properties
@@ -0,0 +1,9 @@
+spring.datasource.url=jdbc:postgresql://localhost:5432/spring-strategy
+spring.datasource.username=postgres
+spring.datasource.password=root
+
+spring.jpa.hibernate.ddl-auto=create-drop
+spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
+#spring.jpa.properties.javax.persistence.schema-generation.create-source=metadata
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=default-naming-strategy-ddl.sql
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/spring-physical-naming-strategy.properties b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/spring-physical-naming-strategy.properties
new file mode 100644
index 0000000000..c9a0c6f24c
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/spring-physical-naming-strategy.properties
@@ -0,0 +1,9 @@
+spring.datasource.url=jdbc:h2:mem:spring-strategy
+spring.datasource.username=sa
+spring.datasource.password=
+
+spring.jpa.hibernate.ddl-auto=create-drop
+spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
+#spring.jpa.properties.javax.persistence.schema-generation.create-source=metadata
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=default-naming-strategy-ddl.sql
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/unquoted-lower-case-naming-strategy-on-postgres.properties b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/unquoted-lower-case-naming-strategy-on-postgres.properties
new file mode 100644
index 0000000000..b22472bd8f
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/unquoted-lower-case-naming-strategy-on-postgres.properties
@@ -0,0 +1,9 @@
+spring.datasource.url=jdbc:postgresql://localhost:5432/unquoted-lower-case-strategy
+spring.datasource.username=postgres
+spring.datasource.password=root
+
+spring.jpa.hibernate.ddl-auto=create-drop
+spring.jpa.hibernate.naming.physical-strategy=com.baeldung.namingstrategy.UnquotedLowerCaseNamingStrategy
+#spring.jpa.properties.javax.persistence.schema-generation.create-source=metadata
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=upper-case-naming-strategy-ddl.sql
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/unquoted-lower-case-naming-strategy.properties b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/unquoted-lower-case-naming-strategy.properties
new file mode 100644
index 0000000000..8083515b4b
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/unquoted-lower-case-naming-strategy.properties
@@ -0,0 +1,9 @@
+spring.datasource.url=jdbc:h2:mem:unquoted-lower-case-strategy
+spring.datasource.username=sa
+spring.datasource.password=
+
+spring.jpa.hibernate.ddl-auto=create-drop
+spring.jpa.hibernate.naming.physical-strategy=com.baeldung.namingstrategy.UnquotedLowerCaseNamingStrategy
+#spring.jpa.properties.javax.persistence.schema-generation.create-source=metadata
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=upper-case-naming-strategy-ddl.sql
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/unquoted-upper-case-naming-strategy-on-postgres.properties b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/unquoted-upper-case-naming-strategy-on-postgres.properties
new file mode 100644
index 0000000000..da03a0d7b5
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/unquoted-upper-case-naming-strategy-on-postgres.properties
@@ -0,0 +1,9 @@
+spring.datasource.url=jdbc:postgresql://localhost:5432/unquoted-upper-case-strategy
+spring.datasource.username=postgres
+spring.datasource.password=root
+
+spring.jpa.hibernate.ddl-auto=create-drop
+spring.jpa.hibernate.naming.physical-strategy=com.baeldung.namingstrategy.UnquotedUpperCaseNamingStrategy
+#spring.jpa.properties.javax.persistence.schema-generation.create-source=metadata
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=upper-case-naming-strategy-ddl.sql
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/unquoted-upper-case-naming-strategy.properties b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/unquoted-upper-case-naming-strategy.properties
new file mode 100644
index 0000000000..d1b63e008c
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-4/src/test/resources/com/baeldung/namingstrategy/unquoted-upper-case-naming-strategy.properties
@@ -0,0 +1,9 @@
+spring.datasource.url=jdbc:h2:mem:unquoted-upper-case-strategy
+spring.datasource.username=sa
+spring.datasource.password=
+
+spring.jpa.hibernate.ddl-auto=create-drop
+spring.jpa.hibernate.naming.physical-strategy=com.baeldung.namingstrategy.UnquotedUpperCaseNamingStrategy
+#spring.jpa.properties.javax.persistence.schema-generation.create-source=metadata
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=upper-case-naming-strategy-ddl.sql
\ No newline at end of file
diff --git a/persistence-modules/spring-hibernate4/README.md b/persistence-modules/spring-hibernate4/README.md
index cfa13ca3b0..a5a72a9b7e 100644
--- a/persistence-modules/spring-hibernate4/README.md
+++ b/persistence-modules/spring-hibernate4/README.md
@@ -9,7 +9,6 @@ This module contains articles about Spring with Hibernate 4
- [Stored Procedures with Hibernate](https://www.baeldung.com/stored-procedures-with-hibernate-tutorial)
- [Hibernate: save, persist, update, merge, saveOrUpdate](https://www.baeldung.com/hibernate-save-persist-update-merge-saveorupdate)
- [Eager/Lazy Loading In Hibernate](https://www.baeldung.com/hibernate-lazy-eager-loading)
-- [The DAO with Spring and Hibernate](https://www.baeldung.com/persistence-layer-with-spring-and-hibernate)
- [Auditing with JPA, Hibernate, and Spring Data JPA](https://www.baeldung.com/database-auditing-jpa)
### Quick Start
diff --git a/persistence-modules/spring-persistence-simple-2/README.md b/persistence-modules/spring-persistence-simple-2/README.md
new file mode 100644
index 0000000000..a6408df8f2
--- /dev/null
+++ b/persistence-modules/spring-persistence-simple-2/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles:
+
+- [Spring JdbcTemplate Unit Testing](https://www.baeldung.com/spring-jdbctemplate-testing)
diff --git a/pom.xml b/pom.xml
index 8d4632fb3e..99d0943582 100644
--- a/pom.xml
+++ b/pom.xml
@@ -453,6 +453,7 @@
java-collections-conversions
java-collections-conversions-2
+ java-collections-maps-3
javafx
@@ -564,6 +565,8 @@
rxjava-libraries
rxjava-observables
rxjava-operators
+
+ atomikos
@@ -803,7 +806,7 @@
jenkins/plugins
jhipster
- jws
+
libraries
@@ -963,6 +966,7 @@
java-collections-conversions
java-collections-conversions-2
+ java-collections-maps-3
javafx
@@ -1073,6 +1077,8 @@
rxjava-libraries
rxjava-observables
rxjava-operators
+
+ atomikos
@@ -1296,7 +1302,7 @@
jenkins/plugins
jhipster
- jws
+
libraries
diff --git a/spring-5-mvc/README.md b/spring-5-mvc/README.md
index e98012c047..aff8bb227c 100644
--- a/spring-5-mvc/README.md
+++ b/spring-5-mvc/README.md
@@ -6,3 +6,4 @@ This module contains articles about Spring 5 model-view-controller (MVC) pattern
- [Spring Boot and Kotlin](https://www.baeldung.com/spring-boot-kotlin)
- [Spring MVC Streaming and SSE Request Processing](https://www.baeldung.com/spring-mvc-sse-streams)
- [Interface Driven Controllers in Spring](https://www.baeldung.com/spring-interface-driven-controllers)
+- [Returning Plain HTML From a Spring MVC Controller](https://www.baeldung.com/spring-mvc-return-html)
diff --git a/spring-batch/README.md b/spring-batch/README.md
index d637de269c..3a89459629 100644
--- a/spring-batch/README.md
+++ b/spring-batch/README.md
@@ -3,6 +3,7 @@
This module contains articles about Spring Batch
### Relevant Articles:
+
- [Introduction to Spring Batch](https://www.baeldung.com/introduction-to-spring-batch)
- [Spring Batch using Partitioner](https://www.baeldung.com/spring-batch-partitioner)
- [Spring Batch – Tasklets vs Chunks](https://www.baeldung.com/spring-batch-tasklet-chunk)
@@ -10,3 +11,4 @@ This module contains articles about Spring Batch
- [Configuring Skip Logic in Spring Batch](https://www.baeldung.com/spring-batch-skip-logic)
- [Testing a Spring Batch Job](https://www.baeldung.com/spring-batch-testing-job)
- [Configuring Retry Logic in Spring Batch](https://www.baeldung.com/spring-batch-retry-logic)
+- [Conditional Flow in Spring Batch](https://www.baeldung.com/spring-batch-conditional-flow)
diff --git a/spring-boot-modules/spring-boot-libraries/pom.xml b/spring-boot-modules/spring-boot-libraries/pom.xml
index 2b1b1b7d12..090967d8a8 100644
--- a/spring-boot-modules/spring-boot-libraries/pom.xml
+++ b/spring-boot-modules/spring-boot-libraries/pom.xml
@@ -28,6 +28,10 @@
org.springframework.boot
spring-boot-starter-tomcat
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
org.springframework.boot
spring-boot-starter-test
diff --git a/spring-boot-modules/spring-boot-libraries/src/main/java/com/baeldung/Application.java b/spring-boot-modules/spring-boot-libraries/src/main/java/com/baeldung/scheduling/shedlock/SpringBootShedlockApplication.java
similarity index 71%
rename from spring-boot-modules/spring-boot-libraries/src/main/java/com/baeldung/Application.java
rename to spring-boot-modules/spring-boot-libraries/src/main/java/com/baeldung/scheduling/shedlock/SpringBootShedlockApplication.java
index 15422e1065..cebb234036 100644
--- a/spring-boot-modules/spring-boot-libraries/src/main/java/com/baeldung/Application.java
+++ b/spring-boot-modules/spring-boot-libraries/src/main/java/com/baeldung/scheduling/shedlock/SpringBootShedlockApplication.java
@@ -1,4 +1,4 @@
-package com.baeldung;
+package com.baeldung.scheduling.shedlock;
import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import org.springframework.boot.SpringApplication;
@@ -8,8 +8,8 @@ import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
-public class Application {
+public class SpringBootShedlockApplication {
public static void main(String[] args) {
- SpringApplication.run(Application.class, args);
+ SpringApplication.run(SpringBootShedlockApplication.class, args);
}
}
diff --git a/spring-caching/pom.xml b/spring-caching/pom.xml
index c3ededbd14..d33f24de1f 100644
--- a/spring-caching/pom.xml
+++ b/spring-caching/pom.xml
@@ -19,6 +19,10 @@
org.springframework
spring-context
+
+ org.springframework.boot
+ spring-boot-starter-cache
+
org.springframework
spring-web
diff --git a/spring-caching/src/main/java/com/baeldung/caching/boot/CacheApplication.java b/spring-caching/src/main/java/com/baeldung/caching/boot/CacheApplication.java
new file mode 100644
index 0000000000..714dc443e0
--- /dev/null
+++ b/spring-caching/src/main/java/com/baeldung/caching/boot/CacheApplication.java
@@ -0,0 +1,14 @@
+package com.baeldung.caching.boot;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
+
+@SpringBootApplication
+@EnableCaching
+public class CacheApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(CacheApplication.class, args);
+ }
+}
diff --git a/spring-caching/src/main/java/com/baeldung/caching/boot/SimpleCacheCustomizer.java b/spring-caching/src/main/java/com/baeldung/caching/boot/SimpleCacheCustomizer.java
new file mode 100644
index 0000000000..a76a01caae
--- /dev/null
+++ b/spring-caching/src/main/java/com/baeldung/caching/boot/SimpleCacheCustomizer.java
@@ -0,0 +1,24 @@
+package com.baeldung.caching.boot;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer;
+import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
+import org.springframework.stereotype.Component;
+
+import static java.util.Arrays.asList;
+
+@Component
+public class SimpleCacheCustomizer implements CacheManagerCustomizer {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SimpleCacheCustomizer.class);
+
+ static final String USERS_CACHE = "users";
+ static final String TRANSACTIONS_CACHE = "transactions";
+
+ @Override
+ public void customize(ConcurrentMapCacheManager cacheManager) {
+ LOGGER.info("Customizing Cache Manager");
+ cacheManager.setCacheNames(asList(USERS_CACHE, TRANSACTIONS_CACHE));
+ }
+}
diff --git a/spring-caching/src/test/java/com/baeldung/caching/boot/SimpleCacheCustomizerIntegrationTest.java b/spring-caching/src/test/java/com/baeldung/caching/boot/SimpleCacheCustomizerIntegrationTest.java
new file mode 100644
index 0000000000..56a4bd4745
--- /dev/null
+++ b/spring-caching/src/test/java/com/baeldung/caching/boot/SimpleCacheCustomizerIntegrationTest.java
@@ -0,0 +1,24 @@
+package com.baeldung.caching.boot;
+
+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.cache.CacheManager;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class SimpleCacheCustomizerIntegrationTest {
+
+ @Autowired
+ private CacheManager cacheManager;
+
+ @Test
+ public void givenCacheManagerCustomizerWhenBootstrappedThenCacheManagerCustomized() {
+ assertThat(cacheManager.getCacheNames())
+ .containsOnly(SimpleCacheCustomizer.USERS_CACHE, SimpleCacheCustomizer.TRANSACTIONS_CACHE);
+ }
+}
\ No newline at end of file
diff --git a/spring-core-2/README.md b/spring-core-2/README.md
index 1fb591f693..947b816db8 100644
--- a/spring-core-2/README.md
+++ b/spring-core-2/README.md
@@ -7,7 +7,6 @@ This module contains articles about core Spring functionality
- [Guide to Spring @Autowired](http://www.baeldung.com/spring-autowire)
- [Spring Profiles](http://www.baeldung.com/spring-profiles)
- [A Spring Custom Annotation for a Better DAO](http://www.baeldung.com/spring-annotation-bean-pre-processor)
-- [Running Setup Data on Startup in Spring](http://www.baeldung.com/running-setup-logic-on-startup-in-spring)
- [Quick Guide to Spring Bean Scopes](http://www.baeldung.com/spring-bean-scopes)
- [Custom Scope in Spring](http://www.baeldung.com/spring-custom-scope)
- [@Order in Spring](http://www.baeldung.com/spring-order)
@@ -15,6 +14,4 @@ This module contains articles about core Spring functionality
- [Spring Events](https://www.baeldung.com/spring-events)
- [Spring Null-Safety Annotations](https://www.baeldung.com/spring-null-safety-annotations)
- [Using @Autowired in Abstract Classes](https://www.baeldung.com/spring-autowired-abstract-class)
-- [Guide to the Spring BeanFactory](https://www.baeldung.com/spring-beanfactory)
-- [Reading HttpServletRequest Multiple Times in Spring](https://www.baeldung.com/spring-reading-httpservletrequest-multiple-times)
- More articles: [[<-- prev]](/spring-core)[[next -->]](/spring-core-3)
diff --git a/spring-core-3/README.md b/spring-core-3/README.md
index b2c4f694a8..6c210b23ef 100644
--- a/spring-core-3/README.md
+++ b/spring-core-3/README.md
@@ -10,4 +10,5 @@ This module contains articles about core Spring functionality
- [Spring – Injecting Collections](https://www.baeldung.com/spring-injecting-collections)
- [Design Patterns in the Spring Framework](https://www.baeldung.com/spring-framework-design-patterns)
- [Injecting a Value in a Static Field in Spring](https://www.baeldung.com/spring-inject-static-field)
+- [Difference Between BeanFactory and ApplicationContext](https://www.baeldung.com/spring-beanfactory-vs-applicationcontext)
- More articles: [[<-- prev]](/spring-core-2)
diff --git a/spring-reactive-kotlin/README.md b/spring-reactive-kotlin/README.md
index 629f7e7f58..d6ce3b7645 100644
--- a/spring-reactive-kotlin/README.md
+++ b/spring-reactive-kotlin/README.md
@@ -4,3 +4,4 @@ This module contains articles about reactive Kotlin
### Relevant Articles:
- [Spring Webflux with Kotlin](https://www.baeldung.com/spring-webflux-kotlin)
+- [Kotlin Reactive Microservice With Spring Boot](https://www.baeldung.com/spring-boot-kotlin-reactive-microservice)
diff --git a/spring-security-modules/spring-security-mvc-login/src/test/java/com/baeldung/SpringContextTest.java b/spring-security-modules/spring-security-mvc-login/src/test/java/com/baeldung/SpringContextTest.java
index 4cf3b736ea..dfc83a40b0 100644
--- a/spring-security-modules/spring-security-mvc-login/src/test/java/com/baeldung/SpringContextTest.java
+++ b/spring-security-modules/spring-security-mvc-login/src/test/java/com/baeldung/SpringContextTest.java
@@ -7,7 +7,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
@RunWith(SpringJUnit4ClassRunner.class)
-@ContextConfiguration({ "/RedirectionWebSecurityConfig.xml", "/mvc-servlet.xml" })
+@ContextConfiguration({ "/RedirectionWebSecurityConfig.xml" })
@WebAppConfiguration
public class SpringContextTest {
@Test
diff --git a/spring-security-modules/spring-security-mvc-login/src/test/java/com/baeldung/security/RedirectionSecurityIntegrationTest.java b/spring-security-modules/spring-security-mvc-login/src/test/java/com/baeldung/security/RedirectionSecurityIntegrationTest.java
index 1235e2e69f..e2b444de20 100644
--- a/spring-security-modules/spring-security-mvc-login/src/test/java/com/baeldung/security/RedirectionSecurityIntegrationTest.java
+++ b/spring-security-modules/spring-security-mvc-login/src/test/java/com/baeldung/security/RedirectionSecurityIntegrationTest.java
@@ -25,7 +25,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class)
-@ContextConfiguration({ "/RedirectionWebSecurityConfig.xml", "/mvc-servlet.xml" })
+@ContextConfiguration({ "/RedirectionWebSecurityConfig.xml" })
@WebAppConfiguration
public class RedirectionSecurityIntegrationTest {
diff --git a/spring-security-modules/spring-security-mvc-login/src/test/resources/mvc-servlet.xml b/spring-security-modules/spring-security-mvc-login/src/test/resources/mvc-servlet.xml
deleted file mode 100644
index aee837c977..0000000000
--- a/spring-security-modules/spring-security-mvc-login/src/test/resources/mvc-servlet.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/spring-security-modules/spring-security-mvc/README.md b/spring-security-modules/spring-security-mvc/README.md
index 7d1a492cd3..bb4cfe1a4f 100644
--- a/spring-security-modules/spring-security-mvc/README.md
+++ b/spring-security-modules/spring-security-mvc/README.md
@@ -10,6 +10,7 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
- [HttpSessionListener Example – Monitoring](https://www.baeldung.com/httpsessionlistener_with_metrics)
- [Control the Session with Spring Security](https://www.baeldung.com/spring-security-session)
+- [The Clear-Site-Data Header in Spring Security](https://www.baeldung.com/spring-security-clear-site-data-header)
### Build the Project
diff --git a/spring-thymeleaf-2/src/main/java/com/baeldung/thymeleaf/mvcdata/BeanConfig.java b/spring-thymeleaf-2/src/main/java/com/baeldung/thymeleaf/mvcdata/BeanConfig.java
new file mode 100644
index 0000000000..19f0101cf2
--- /dev/null
+++ b/spring-thymeleaf-2/src/main/java/com/baeldung/thymeleaf/mvcdata/BeanConfig.java
@@ -0,0 +1,14 @@
+package com.baeldung.thymeleaf.mvcdata;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.baeldung.thymeleaf.mvcdata.repository.EmailData;
+
+@Configuration
+public class BeanConfig {
+ @Bean
+ public EmailData emailData() {
+ return new EmailData();
+ }
+}
diff --git a/spring-thymeleaf-2/src/main/java/com/baeldung/thymeleaf/mvcdata/EmailController.java b/spring-thymeleaf-2/src/main/java/com/baeldung/thymeleaf/mvcdata/EmailController.java
new file mode 100644
index 0000000000..1bfe3f3428
--- /dev/null
+++ b/spring-thymeleaf-2/src/main/java/com/baeldung/thymeleaf/mvcdata/EmailController.java
@@ -0,0 +1,63 @@
+package com.baeldung.thymeleaf.mvcdata;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import com.baeldung.thymeleaf.mvcdata.repository.EmailData;
+
+@Controller
+public class EmailController {
+ private EmailData emailData = new EmailData();
+ private ServletContext servletContext;
+
+ public EmailController(ServletContext servletContext) {
+ this.servletContext = servletContext;
+ }
+
+ @GetMapping(value = "/email/modelattributes")
+ public String emailModel(Model model) {
+ model.addAttribute("emaildata", emailData);
+ return "mvcdata/email-model-attributes";
+ }
+
+ @ModelAttribute("emailModelAttribute")
+ EmailData emailModelAttribute() {
+ return emailData;
+ }
+
+ @GetMapping(value = "/email/requestparameters")
+ public String emailRequestParameters(
+ @RequestParam(value = "emailsubject") String emailSubject,
+ @RequestParam(value = "emailcontent") String emailContent,
+ @RequestParam(value = "emailaddress") String emailAddress1,
+ @RequestParam(value = "emailaddress") String emailAddress2,
+ @RequestParam(value = "emaillocale") String emailLocale) {
+ return "mvcdata/email-request-parameters";
+ }
+
+ @GetMapping("/email/sessionattributes")
+ public String emailSessionAttributes(HttpSession httpSession) {
+ httpSession.setAttribute("emaildata", emailData);
+ return "mvcdata/email-session-attributes";
+ }
+
+ @GetMapping("/email/servletcontext")
+ public String emailServletContext() {
+ servletContext.setAttribute("emailsubject", emailData.getEmailSubject());
+ servletContext.setAttribute("emailcontent", emailData.getEmailBody());
+ servletContext.setAttribute("emailaddress", emailData.getEmailAddress1());
+ servletContext.setAttribute("emaillocale", emailData.getEmailLocale());
+ return "mvcdata/email-servlet-context";
+ }
+
+ @GetMapping("/email/beandata")
+ public String emailBeanData() {
+ return "mvcdata/email-bean-data";
+ }
+}
diff --git a/spring-thymeleaf-2/src/main/java/com/baeldung/thymeleaf/mvcdata/repository/EmailData.java b/spring-thymeleaf-2/src/main/java/com/baeldung/thymeleaf/mvcdata/repository/EmailData.java
new file mode 100644
index 0000000000..9dc25bdaa7
--- /dev/null
+++ b/spring-thymeleaf-2/src/main/java/com/baeldung/thymeleaf/mvcdata/repository/EmailData.java
@@ -0,0 +1,48 @@
+package com.baeldung.thymeleaf.mvcdata.repository;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+public class EmailData implements Serializable {
+ private String emailSubject;
+ private String emailBody;
+ private String emailLocale;
+ private String emailAddress1;
+ private String emailAddress2;
+
+ public EmailData() {
+ this.emailSubject = "You have received a new message";
+ this.emailBody = "Good morning !";
+ this.emailLocale = "en-US";
+ this.emailAddress1 = "jhon.doe@example.com";
+ this.emailAddress2 = "mark.jakob@example.com";
+ }
+
+ public String getEmailSubject() {
+ return this.emailSubject;
+ }
+
+ public String getEmailBody() {
+ return this.emailBody;
+ }
+
+ public String getEmailLocale() {
+ return this.emailLocale;
+ }
+
+ public String getEmailAddress1() {
+ return this.emailAddress1;
+ }
+
+ public String getEmailAddress2() {
+ return this.emailAddress2;
+ }
+
+ public List getEmailAddresses() {
+ List emailAddresses = new ArrayList<>();
+ emailAddresses.add(getEmailAddress1());
+ emailAddresses.add(getEmailAddress2());
+ return emailAddresses;
+ }
+}
diff --git a/spring-thymeleaf-2/src/main/resources/templates/mvcdata/email-bean-data.html b/spring-thymeleaf-2/src/main/resources/templates/mvcdata/email-bean-data.html
new file mode 100644
index 0000000000..59073b51c6
--- /dev/null
+++ b/spring-thymeleaf-2/src/main/resources/templates/mvcdata/email-bean-data.html
@@ -0,0 +1,14 @@
+
+
+
+ Subject
+ Subject
+ Content
+ Body
+ Email address
+ Email address
+ Language
+ Language
+
+
\ No newline at end of file
diff --git a/spring-thymeleaf-2/src/main/resources/templates/mvcdata/email-model-attributes.html b/spring-thymeleaf-2/src/main/resources/templates/mvcdata/email-model-attributes.html
new file mode 100644
index 0000000000..caf136383a
--- /dev/null
+++ b/spring-thymeleaf-2/src/main/resources/templates/mvcdata/email-model-attributes.html
@@ -0,0 +1,16 @@
+
+
+
+ Subject
+ Subject
+ Content
+
+ Email addresses
+
+
+
+ Language
+
+
+
\ No newline at end of file
diff --git a/spring-thymeleaf-2/src/main/resources/templates/mvcdata/email-request-parameters.html b/spring-thymeleaf-2/src/main/resources/templates/mvcdata/email-request-parameters.html
new file mode 100644
index 0000000000..8bcd3e1c62
--- /dev/null
+++ b/spring-thymeleaf-2/src/main/resources/templates/mvcdata/email-request-parameters.html
@@ -0,0 +1,20 @@
+
+
+
+ Subject
+ Subject
+ Content
+
+ Email addresses
+
+
+
+ Email address 1
+
+ Email address 2
+
+ Language
+
+
+
\ No newline at end of file
diff --git a/spring-thymeleaf-2/src/main/resources/templates/mvcdata/email-servlet-context.html b/spring-thymeleaf-2/src/main/resources/templates/mvcdata/email-servlet-context.html
new file mode 100644
index 0000000000..b07573047e
--- /dev/null
+++ b/spring-thymeleaf-2/src/main/resources/templates/mvcdata/email-servlet-context.html
@@ -0,0 +1,14 @@
+
+
+
+ Subject
+
+ Content
+
+ Email address
+
+ Language
+
+
+
\ No newline at end of file
diff --git a/spring-thymeleaf-2/src/main/resources/templates/mvcdata/email-session-attributes.html b/spring-thymeleaf-2/src/main/resources/templates/mvcdata/email-session-attributes.html
new file mode 100644
index 0000000000..9227171fc6
--- /dev/null
+++ b/spring-thymeleaf-2/src/main/resources/templates/mvcdata/email-session-attributes.html
@@ -0,0 +1,14 @@
+
+
+
+ Subject
+
+ Content
+
+ Email address
+
+ Language
+
+
+
\ No newline at end of file
diff --git a/spring-thymeleaf-2/src/test/java/com/baeldung/thymeleaf/mvcdata/EmailControllerUnitTest.java b/spring-thymeleaf-2/src/test/java/com/baeldung/thymeleaf/mvcdata/EmailControllerUnitTest.java
new file mode 100644
index 0000000000..5e1190e174
--- /dev/null
+++ b/spring-thymeleaf-2/src/test/java/com/baeldung/thymeleaf/mvcdata/EmailControllerUnitTest.java
@@ -0,0 +1,72 @@
+package com.baeldung.thymeleaf.mvcdata;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+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.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+
+import com.baeldung.thymeleaf.mvcdata.repository.EmailData;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@AutoConfigureMockMvc(printOnlyOnFailure = false)
+public class EmailControllerUnitTest {
+
+ EmailData emailData = new EmailData();
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Test
+ public void whenCallModelAttributes_thenReturnEmailData() throws Exception {
+ mockMvc.perform(MockMvcRequestBuilders.get("/email/modelattributes"))
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("You have received a new message")));
+ }
+
+ @Test
+ public void whenCallRequestParameters_thenReturnEmailData() throws Exception {
+ MultiValueMap params = new LinkedMultiValueMap<>();
+ params.add("emailsubject", emailData.getEmailSubject());
+ params.add("emailcontent", emailData.getEmailBody());
+ params.add("emailaddress", emailData.getEmailAddress1());
+ params.add("emailaddress", emailData.getEmailAddress2());
+ params.add("emaillocale", emailData.getEmailLocale());
+ mockMvc.perform(MockMvcRequestBuilders.get("/email/requestparameters")
+ .params(params))
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("en-US")));
+ }
+
+ @Test
+ public void whenCallSessionAttributes_thenReturnEmailData() throws Exception {
+ mockMvc.perform(MockMvcRequestBuilders.get("/email/sessionattributes"))
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("Good morning !")));
+ }
+
+ @Test
+ public void whenCallServletContext_thenReturnEmailData() throws Exception {
+ mockMvc.perform(MockMvcRequestBuilders.get("/email/servletcontext"))
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("jhon.doe@example.com")));
+ }
+
+ @Test
+ public void whenCallBeanData_thenReturnEmailData() throws Exception {
+ mockMvc.perform(MockMvcRequestBuilders.get("/email/beandata"))
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("jhon.doe@example.com")));
+ }
+
+}
diff --git a/spring-thymeleaf-3/README.md b/spring-thymeleaf-3/README.md
index e1ddd727d7..a8e234b067 100644
--- a/spring-thymeleaf-3/README.md
+++ b/spring-thymeleaf-3/README.md
@@ -2,4 +2,5 @@
This module contains articles about Spring with Thymeleaf
-## Relevant Articles:
\ No newline at end of file
+## Relevant Articles:
+- [Add CSS and JS to Thymeleaf](https://www.baeldung.com/spring-thymeleaf-css-js)
diff --git a/testing-modules/junit5-annotations/pom.xml b/testing-modules/junit5-annotations/pom.xml
index d0fba4d21b..9e51d0ab55 100644
--- a/testing-modules/junit5-annotations/pom.xml
+++ b/testing-modules/junit5-annotations/pom.xml
@@ -46,12 +46,19 @@
${junit.platform.version}
test
+
+ org.assertj
+ assertj-core
+ ${assertj-core.version}
+ test
+
- 5.6.0
+ 5.6.2
1.6.0
2.8.2
+ 3.11.1
diff --git a/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/templates/UserIdGenerator.java b/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/templates/UserIdGenerator.java
new file mode 100644
index 0000000000..f19adb13c8
--- /dev/null
+++ b/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/templates/UserIdGenerator.java
@@ -0,0 +1,5 @@
+package com.baeldung.junit5.templates;
+
+public interface UserIdGenerator {
+ String generate(String firstName, String lastName);
+}
diff --git a/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/templates/UserIdGeneratorImpl.java b/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/templates/UserIdGeneratorImpl.java
new file mode 100644
index 0000000000..b39b07bc4b
--- /dev/null
+++ b/testing-modules/junit5-annotations/src/main/java/com/baeldung/junit5/templates/UserIdGeneratorImpl.java
@@ -0,0 +1,15 @@
+package com.baeldung.junit5.templates;
+
+public class UserIdGeneratorImpl implements UserIdGenerator {
+ private boolean isFeatureEnabled;
+
+ public UserIdGeneratorImpl(boolean isFeatureEnabled) {
+ this.isFeatureEnabled = isFeatureEnabled;
+ }
+
+ public String generate(String firstName, String lastName) {
+ String initialAndLastName = firstName.substring(0, 1)
+ .concat(lastName);
+ return isFeatureEnabled ? "bael".concat(initialAndLastName) : initialAndLastName;
+ }
+}
diff --git a/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/templates/DisabledOnQAEnvironmentExtension.java b/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/templates/DisabledOnQAEnvironmentExtension.java
new file mode 100644
index 0000000000..cd8b7b677d
--- /dev/null
+++ b/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/templates/DisabledOnQAEnvironmentExtension.java
@@ -0,0 +1,27 @@
+package com.baeldung.junit5.templates;
+
+import org.junit.jupiter.api.extension.ConditionEvaluationResult;
+import org.junit.jupiter.api.extension.ExecutionCondition;
+import org.junit.jupiter.api.extension.ExtensionContext;
+
+import java.io.IOException;
+import java.util.Properties;
+
+public class DisabledOnQAEnvironmentExtension implements ExecutionCondition {
+ @Override
+ public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
+ Properties properties = new Properties();
+ try {
+ properties.load(DisabledOnQAEnvironmentExtension.class.getClassLoader()
+ .getResourceAsStream("application.properties"));
+ if ("qa".equalsIgnoreCase(properties.getProperty("env"))) {
+ String reason = String.format("The test '%s' is disabled on QA environment", context.getDisplayName());
+ System.out.println(reason);
+ return ConditionEvaluationResult.disabled(reason);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return ConditionEvaluationResult.enabled("Test enabled");
+ }
+}
\ No newline at end of file
diff --git a/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/templates/GenericTypedParameterResolver.java b/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/templates/GenericTypedParameterResolver.java
new file mode 100644
index 0000000000..76321be101
--- /dev/null
+++ b/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/templates/GenericTypedParameterResolver.java
@@ -0,0 +1,26 @@
+package com.baeldung.junit5.templates;
+
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ParameterContext;
+import org.junit.jupiter.api.extension.ParameterResolutionException;
+import org.junit.jupiter.api.extension.ParameterResolver;
+
+public class GenericTypedParameterResolver implements ParameterResolver {
+ T data;
+
+ public GenericTypedParameterResolver(T data) {
+ this.data = data;
+ }
+
+ @Override
+ public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+ return parameterContext.getParameter()
+ .getType()
+ .isInstance(data);
+ }
+
+ @Override
+ public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+ return data;
+ }
+}
diff --git a/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/templates/UserIdGeneratorImplUnitTest.java b/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/templates/UserIdGeneratorImplUnitTest.java
new file mode 100644
index 0000000000..a2306154a6
--- /dev/null
+++ b/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/templates/UserIdGeneratorImplUnitTest.java
@@ -0,0 +1,18 @@
+package com.baeldung.junit5.templates;
+
+import org.junit.jupiter.api.TestTemplate;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class UserIdGeneratorImplUnitTest {
+ @TestTemplate
+ @ExtendWith(UserIdGeneratorTestInvocationContextProvider.class)
+ public void whenUserIdRequested_thenUserIdIsReturnedInCorrectFormat(UserIdGeneratorTestCase testCase) {
+ UserIdGenerator userIdGenerator = new UserIdGeneratorImpl(testCase.isFeatureEnabled());
+
+ String actualUserId = userIdGenerator.generate(testCase.getFirstName(), testCase.getLastName());
+
+ assertThat(actualUserId).isEqualTo(testCase.getExpectedUserId());
+ }
+}
\ No newline at end of file
diff --git a/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/templates/UserIdGeneratorTestCase.java b/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/templates/UserIdGeneratorTestCase.java
new file mode 100644
index 0000000000..dd41dd5a27
--- /dev/null
+++ b/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/templates/UserIdGeneratorTestCase.java
@@ -0,0 +1,37 @@
+package com.baeldung.junit5.templates;
+
+public class UserIdGeneratorTestCase {
+ private String displayName;
+ private boolean isFeatureEnabled;
+ private String firstName;
+ private String lastName;
+ private String expectedUserId;
+
+ public UserIdGeneratorTestCase(String displayName, boolean isFeatureEnabled, String firstName, String lastName, String expectedUserId) {
+ this.displayName = displayName;
+ this.isFeatureEnabled = isFeatureEnabled;
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.expectedUserId = expectedUserId;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public boolean isFeatureEnabled() {
+ return isFeatureEnabled;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public String getExpectedUserId() {
+ return expectedUserId;
+ }
+}
diff --git a/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/templates/UserIdGeneratorTestInvocationContextProvider.java b/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/templates/UserIdGeneratorTestInvocationContextProvider.java
new file mode 100644
index 0000000000..277ec03f05
--- /dev/null
+++ b/testing-modules/junit5-annotations/src/test/java/com/baeldung/junit5/templates/UserIdGeneratorTestInvocationContextProvider.java
@@ -0,0 +1,87 @@
+package com.baeldung.junit5.templates;
+
+import org.junit.jupiter.api.extension.*;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+import static java.util.Arrays.asList;
+
+public class UserIdGeneratorTestInvocationContextProvider implements TestTemplateInvocationContextProvider {
+
+ @Override
+ public boolean supportsTestTemplate(ExtensionContext extensionContext) {
+ return true;
+ }
+
+ @Override
+ public Stream provideTestTemplateInvocationContexts(ExtensionContext extensionContext) {
+ boolean featureDisabled = false;
+ boolean featureEnabled = true;
+ return Stream.of(
+ featureDisabledContext(
+ new UserIdGeneratorTestCase(
+ "Given feature switch disabled When user name is John Smith Then generated userid is JSmith",
+ featureDisabled, "John", "Smith", "JSmith")),
+ featureEnabledContext(
+ new UserIdGeneratorTestCase(
+ "Given feature switch enabled When user name is John Smith Then generated userid is baelJSmith",
+ featureEnabled, "John", "Smith", "baelJSmith"))
+ );
+ }
+
+ private TestTemplateInvocationContext featureDisabledContext(UserIdGeneratorTestCase userIdGeneratorTestCase) {
+ return new TestTemplateInvocationContext() {
+ @Override
+ public String getDisplayName(int invocationIndex) {
+ return userIdGeneratorTestCase.getDisplayName();
+ }
+
+ @Override
+ public List getAdditionalExtensions() {
+ return asList(
+ new GenericTypedParameterResolver(userIdGeneratorTestCase),
+ new BeforeTestExecutionCallback() {
+ @Override
+ public void beforeTestExecution(ExtensionContext extensionContext) {
+ System.out.println("BeforeTestExecutionCallback:Disabled context");
+ }
+ },
+ new AfterTestExecutionCallback() {
+ @Override
+ public void afterTestExecution(ExtensionContext extensionContext) {
+ System.out.println("AfterTestExecutionCallback:Disabled context");
+ }
+ });
+ }
+ };
+ }
+
+ private TestTemplateInvocationContext featureEnabledContext(UserIdGeneratorTestCase userIdGeneratorTestCase) {
+ return new TestTemplateInvocationContext() {
+ @Override
+ public String getDisplayName(int invocationIndex) {
+ return userIdGeneratorTestCase.getDisplayName();
+ }
+
+ @Override
+ public List getAdditionalExtensions() {
+ return asList(
+ new GenericTypedParameterResolver(userIdGeneratorTestCase),
+ new DisabledOnQAEnvironmentExtension(),
+ new BeforeEachCallback() {
+ @Override
+ public void beforeEach(ExtensionContext extensionContext) {
+ System.out.println("BeforeEachCallback:Enabled context");
+ }
+ },
+ new AfterEachCallback() {
+ @Override
+ public void afterEach(ExtensionContext extensionContext) {
+ System.out.println("AfterEachCallback:Enabled context");
+ }
+ });
+ }
+ };
+ }
+}
diff --git a/testing-modules/junit5-annotations/src/test/resources/application.properties b/testing-modules/junit5-annotations/src/test/resources/application.properties
new file mode 100644
index 0000000000..bbfa14d866
--- /dev/null
+++ b/testing-modules/junit5-annotations/src/test/resources/application.properties
@@ -0,0 +1 @@
+env=qa
\ No newline at end of file