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