diff --git a/aws-modules/aws-lambda-modules/lambda-function/pom.xml b/aws-modules/aws-lambda-modules/lambda-function/pom.xml
index a82209b23f..9fff7d1d9a 100644
--- a/aws-modules/aws-lambda-modules/lambda-function/pom.xml
+++ b/aws-modules/aws-lambda-modules/lambda-function/pom.xml
@@ -3,9 +3,9 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- lambda
+ lambda-function
0.1.0-SNAPSHOT
- lambda
+ lambda-function
jar
diff --git a/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/regex/aftermatch/GetTextAfterTheRegexMatchUnitTest.java b/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/regex/aftermatch/GetTextAfterTheRegexMatchUnitTest.java
new file mode 100644
index 0000000000..04650a0c02
--- /dev/null
+++ b/core-java-modules/core-java-regex-2/src/test/java/com/baeldung/regex/aftermatch/GetTextAfterTheRegexMatchUnitTest.java
@@ -0,0 +1,83 @@
+package com.baeldung.regex.aftermatch;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class GetTextAfterTheRegexMatchUnitTest {
+ private static final String INPUT1 = "Some text, targetValue=Regex is cool";
+ private static final String INPUT2 = "Some text. targetValue=Java is cool. some other text";
+
+ @Test
+ void whenUsingSplit_thenGetExpectedString() {
+ String result1 = INPUT1.split("targetValue=")[1];
+ assertEquals("Regex is cool", result1);
+
+ String afterFirstSplit = INPUT2.split("targetValue=")[1];
+ assertEquals("Java is cool. some other text", afterFirstSplit);
+ String result2 = afterFirstSplit.split("[.]")[0];
+ assertEquals("Java is cool", result2);
+
+ // if use the dot as the regex for splitting, the result array is empty
+ String[] splitByDot = INPUT2.split("targetValue=")[1].split(".");
+ assertEquals(0, splitByDot.length);
+ }
+
+ @Test
+ void whenUsingReplaceAll_thenGetExpectedString() {
+ String result1 = INPUT1.replaceAll(".*targetValue=", "");
+ assertEquals("Regex is cool", result1);
+
+ String afterFirstReplace = INPUT2.replaceAll(".*targetValue=", "");
+ assertEquals("Java is cool. some other text", afterFirstReplace);
+ String result2 = afterFirstReplace.replaceAll("[.].*", "");
+ assertEquals("Java is cool", result2);
+
+ }
+
+ @Test
+ void whenUsingRegexGrouping_thenGetExpectedString() {
+ Pattern p1 = Pattern.compile("targetValue=(.*)");
+ Matcher m1 = p1.matcher(INPUT1);
+ assertTrue(m1.find());
+ String result1 = m1.group(1);
+ assertEquals("Regex is cool", result1);
+
+ Pattern p2 = Pattern.compile("targetValue=([^.]*)");
+ Matcher m2 = p2.matcher(INPUT2);
+ assertTrue(m2.find());
+ String result2 = m2.group(1);
+ assertEquals("Java is cool", result2);
+
+ Pattern p3 = Pattern.compile("targetValue=(.*?)[.]");
+ Matcher m3 = p3.matcher(INPUT2);
+ assertTrue(m3.find());
+ String result3 = m3.group(1);
+ assertEquals("Java is cool", result3);
+ }
+
+ @Test
+ void whenUsingLookaround_thenGetExpectedString() {
+ Pattern p1 = Pattern.compile("(?<=targetValue=).*");
+ Matcher m1 = p1.matcher(INPUT1);
+ assertTrue(m1.find());
+ String result1 = m1.group();
+ assertEquals("Regex is cool", result1);
+
+ Pattern p2 = Pattern.compile("(?<=targetValue=)[^.]*");
+ Matcher m2 = p2.matcher(INPUT2);
+ assertTrue(m2.find());
+ String result2 = m2.group();
+ assertEquals("Java is cool", result2);
+
+ Pattern p3 = Pattern.compile("(?<=targetValue=).*(?=[.])");
+ Matcher m3 = p3.matcher(INPUT2);
+ assertTrue(m3.find());
+ String result3 = m3.group();
+ assertEquals("Java is cool", result3);
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-string-algorithms-3/pom.xml b/core-java-modules/core-java-string-algorithms-3/pom.xml
index 74a9486ec0..7d4adeba92 100644
--- a/core-java-modules/core-java-string-algorithms-3/pom.xml
+++ b/core-java-modules/core-java-string-algorithms-3/pom.xml
@@ -39,8 +39,8 @@
maven-compiler-plugin
${maven-compiler-plugin.version}
- ${java.version}
- ${java.version}
+ ${maven.compiler.source}
+ ${maven.compiler.target}
-parameters
diff --git a/core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/charfreq/CharacterWithHighestFrequency.java b/core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/charfreq/CharacterWithHighestFrequency.java
new file mode 100644
index 0000000000..938ad1edf3
--- /dev/null
+++ b/core-java-modules/core-java-string-algorithms-3/src/main/java/com/baeldung/charfreq/CharacterWithHighestFrequency.java
@@ -0,0 +1,58 @@
+package com.baeldung.charfreq;
+
+import static java.util.Map.Entry.comparingByValue;
+import static java.util.stream.Collectors.counting;
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.toSet;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+public class CharacterWithHighestFrequency {
+ public static Character byStream(String input) {
+ return input.chars()
+ .mapToObj(x -> (char) x)
+ .collect(groupingBy(x -> x, counting()))
+ .entrySet()
+ .stream()
+ .max(comparingByValue())
+ .get()
+ .getKey();
+ }
+
+ public static Set byMap(String input) {
+ Map map = new HashMap<>();
+ for (char c : input.toCharArray()) {
+ map.compute(c, (character, count) -> count == null ? 1 : ++count);
+ }
+ int maxCount = map.values()
+ .stream()
+ .mapToInt(Integer::intValue)
+ .max()
+ .getAsInt();
+
+ return map.keySet()
+ .stream()
+ .filter(c -> map.get(c) == maxCount)
+ .collect(toSet());
+ }
+
+ public static Set byBucket(String input) {
+ int[] buckets = new int[128];
+
+ int maxCount = 0;
+ for (char c : input.toCharArray()) {
+ buckets[c]++;
+ maxCount = Math.max(buckets[c], maxCount);
+ }
+
+ int finalMaxCount = maxCount;
+ return IntStream.range(0, 128)
+ .filter(c -> buckets[c] == finalMaxCount)
+ .mapToObj(i -> (char) i)
+ .collect(Collectors.toSet());
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/charfreq/CharacterWithHighestFrequencyUnitTest.java b/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/charfreq/CharacterWithHighestFrequencyUnitTest.java
new file mode 100644
index 0000000000..978752f3d4
--- /dev/null
+++ b/core-java-modules/core-java-string-algorithms-3/src/test/java/com/baeldung/charfreq/CharacterWithHighestFrequencyUnitTest.java
@@ -0,0 +1,43 @@
+package com.baeldung.charfreq;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+class CharacterWithHighestFrequencyUnitTest {
+ private static final String INPUT1 = "aaaaaaaaaa(10) bbbbbbb ccccc dddd eee ff";
+ private static final Set EXPECTED1 = Collections.singleton('a');
+
+ private static final String INPUT2 = "YYYYYYY(7) bbbbb -------(7) dddd eee kkkkkkk(7) ff";
+ private static final Set EXPECTED2 = ImmutableSet.of('Y', '-', 'k');
+
+ @Test
+ void whenGettingSingleCharWithHighestFrequencyByStream_shouldSuccess() {
+ char result1 = CharacterWithHighestFrequency.byStream(INPUT1);
+ assertEquals('a', result1);
+ }
+
+ @Test
+ void whenGettingCharWithHighestFrequencyByMap_shouldSuccess() {
+ Set result1 = CharacterWithHighestFrequency.byMap(INPUT1);
+ assertEquals(EXPECTED1, result1);
+
+ Set result2 = CharacterWithHighestFrequency.byMap(INPUT2);
+ assertEquals(EXPECTED2, result2);
+
+ }
+
+ @Test
+ void whenGettingCharWithHighestFrequencyByBucket_shouldSuccess() {
+ Set result1 = CharacterWithHighestFrequency.byBucket(INPUT1);
+ assertEquals(EXPECTED1, result1);
+
+ Set result2 = CharacterWithHighestFrequency.byBucket(INPUT2);
+ assertEquals(EXPECTED2, result2);
+ }
+}
\ No newline at end of file
diff --git a/libraries-data-db/src/main/java/com/baeldung/libraries/h2/H2InitDemoApplication.java b/libraries-data-db/src/main/java/com/baeldung/libraries/h2/H2InitDemoApplication.java
new file mode 100644
index 0000000000..36170fb263
--- /dev/null
+++ b/libraries-data-db/src/main/java/com/baeldung/libraries/h2/H2InitDemoApplication.java
@@ -0,0 +1,72 @@
+package com.baeldung.libraries.h2;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.ApplicationContext;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.DriverManager;
+
+@SpringBootApplication
+public class H2InitDemoApplication {
+
+ public static void main(String[] args) {
+ ApplicationContext ctx = SpringApplication.run(H2InitDemoApplication.class, args);
+ initDatabaseUsingPlainJDBCWithURL();
+ initDatabaseUsingPlainJDBCWithFile();
+ initDatabaseUsingSpring(ctx.getBean(DataSource.class));
+ }
+
+ /**
+ * Initialize in-memory database using plain JDBC and SQL
+ * statements in the URL.
+ */
+ private static void initDatabaseUsingPlainJDBCWithURL() {
+ try (Connection conn = DriverManager.
+ getConnection("jdbc:h2:mem:baeldung;INIT=CREATE SCHEMA IF NOT EXISTS baeldung\\;SET SCHEMA baeldung;",
+ "admin",
+ "password")) {
+ conn.createStatement().execute("create table users (name VARCHAR(100) NOT NULL, email VARCHAR(100) NOT NULL);");
+ System.out.println("Created table users");
+ conn.createStatement().execute("insert into users (name, email) values ('Mike', 'mike@baeldung.com')");
+ System.out.println("Added user mike");
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Initialize in-memory database using plain JDBC and SQL
+ * statements in a file.
+ */
+ private static void initDatabaseUsingPlainJDBCWithFile() {
+ try (Connection conn = DriverManager.
+ getConnection("jdbc:h2:mem:baeldung;INIT=RUNSCRIPT FROM 'src/main/resources/h2init.sql';",
+ "admin",
+ "password")) {
+ conn.createStatement().execute("insert into users (name, email) values ('Mike', 'mike@baeldung.com')");
+ System.out.println("Added user mike");
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Initialize in-memory database using Spring Boot
+ * properties. See article for full details of required
+ * properties for this method to work.
+ */
+ private static void initDatabaseUsingSpring(DataSource ds) {
+ try (Connection conn = ds.getConnection()) {
+ conn.createStatement().execute("insert into users (name, email) values ('Mike', 'mike@baeldung.com')");
+ System.out.println("Added user mike");
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
+
diff --git a/libraries-data-db/src/main/resources/h2init.sql b/libraries-data-db/src/main/resources/h2init.sql
new file mode 100644
index 0000000000..c6fb70bcc4
--- /dev/null
+++ b/libraries-data-db/src/main/resources/h2init.sql
@@ -0,0 +1,3 @@
+CREATE SCHEMA IF NOT EXISTS baeldung;
+SET SCHEMA baeldung;
+CREATE TABLE users (name VARCHAR(100) NOT NULL, email VARCHAR(100) NOT NULL);
diff --git a/messaging-modules/spring-jms/pom.xml b/messaging-modules/spring-jms/pom.xml
index 2dee95136d..ef1e0cb3a8 100644
--- a/messaging-modules/spring-jms/pom.xml
+++ b/messaging-modules/spring-jms/pom.xml
@@ -44,19 +44,19 @@
org.mockito
mockito-core
- 4.6.1
+ ${mockito-core.version}
test
org.apache.activemq.tooling
activemq-junit
- 5.16.5
+ ${activemq-junit.version}
test
org.testcontainers
testcontainers
- 1.17.3
+ ${testcontainers.version}
test
@@ -83,6 +83,9 @@
5.14.1
1.5.10.RELEASE
3.3.2
+ 4.6.1
+ 5.16.5
+ 1.17.3
\ No newline at end of file
diff --git a/microservices-modules/rest-express/pom.xml b/microservices-modules/rest-express/pom.xml
index e3fed19e29..eda27ec164 100644
--- a/microservices-modules/rest-express/pom.xml
+++ b/microservices-modules/rest-express/pom.xml
@@ -23,15 +23,6 @@
rest-express
jar
-
- 0.3.3
- 3.1.2
- 2.6
- 0.11.3
- 1.0
- 0.4.8
- 4.11
-
@@ -98,7 +89,7 @@
org.codehaus.mojo
exec-maven-plugin
- 1.2.1
+ ${exec-maven-plugin.version}
com.baeldung.restexpress.Main
@@ -106,7 +97,7 @@
org.apache.maven.plugins
maven-shade-plugin
- 2.4.1
+ ${maven-shade-plugin.version}
false
@@ -140,8 +131,22 @@
org.codehaus.mojo
versions-maven-plugin
- 2.0
+ ${versions-maven-plugin.version}
+
+
+ 0.3.3
+ 3.1.2
+ 2.6
+ 0.11.3
+ 1.0
+ 0.4.8
+ 4.11
+ 1.2.1
+ 2.4.1
+ 2.0
+
+
diff --git a/persistence-modules/hibernate-exceptions/src/test/java/com/baeldung/hibernate/exception/detachedentity/DetachedEntityUnitTest.java b/persistence-modules/hibernate-exceptions/src/test/java/com/baeldung/hibernate/exception/detachedentity/DetachedEntityUnitTest.java
index c10b319319..cb4313c537 100644
--- a/persistence-modules/hibernate-exceptions/src/test/java/com/baeldung/hibernate/exception/detachedentity/DetachedEntityUnitTest.java
+++ b/persistence-modules/hibernate-exceptions/src/test/java/com/baeldung/hibernate/exception/detachedentity/DetachedEntityUnitTest.java
@@ -42,7 +42,7 @@ public class DetachedEntityUnitTest {
assertThatThrownBy(() -> session.persist(detachedPost))
.isInstanceOf(PersistenceException.class)
- .hasMessageContaining("`org.hibernate.PersistentObjectException` to JPA `PersistenceException` : detached entity passed to persist");
+ .hasMessageContaining("detached entity passed to persist: com.baeldung.hibernate.exception.detachedentity.entity.Post");
}
@Test
@@ -71,13 +71,13 @@ public class DetachedEntityUnitTest {
assertThatThrownBy(() -> session.persist(detachedPost))
.isInstanceOf(PersistenceException.class)
- .hasMessageContaining("`org.hibernate.PersistentObjectException` to JPA `PersistenceException` : detached entity passed to persist");
+ .hasMessageContaining("detached entity passed to persist: com.baeldung.hibernate.exception.detachedentity.entity.Post");
}
@Test
public void givenDetachedPost_whenMergeAndPersistComment_thenNoExceptionIsThrown() {
Comment comment = new Comment("nice article!");
- Post mergedPost = (Post) session.merge(detachedPost);
+ Post mergedPost = session.merge(detachedPost);
comment.setPost(mergedPost);
session.persist(comment);
diff --git a/persistence-modules/hibernate-jpa/src/test/java/com/baeldung/hibernate/entitymanager/getreference/GetReferenceH2IntegrationTest.java b/persistence-modules/hibernate-jpa/src/test/java/com/baeldung/hibernate/entitymanager/getreference/GetReferenceH2IntegrationTest.java
index 02744c8ee5..86f059c6d7 100644
--- a/persistence-modules/hibernate-jpa/src/test/java/com/baeldung/hibernate/entitymanager/getreference/GetReferenceH2IntegrationTest.java
+++ b/persistence-modules/hibernate-jpa/src/test/java/com/baeldung/hibernate/entitymanager/getreference/GetReferenceH2IntegrationTest.java
@@ -136,9 +136,6 @@ public class GetReferenceH2IntegrationTest {
});
StringBuilder expected = new StringBuilder();
- expected.append("Hibernate: select ");
- expected.append("p1_0.id,g1_0.id,g1_0.name,p1_0.name ");
- expected.append("from Player p1_0 left join Game g1_0 on g1_0.id=p1_0.game_id where p1_0.id=?" + System.lineSeparator());
expected.append("Hibernate: delete from Player where id=?" + System.lineSeparator());
assertEquals(expected.toString(), output.toString());
@@ -161,7 +158,7 @@ public class GetReferenceH2IntegrationTest {
expected.append("Hibernate: select ");
expected.append("p1_0.id,g1_0.id,g1_0.name,p1_0.name ");
expected.append("from Player p1_0 left join Game g1_0 on g1_0.id=p1_0.game_id where p1_0.id=?" + System.lineSeparator());
- expected.append("Hibernate: update Player set game_id=?, name=? where id=?" + System.lineSeparator());
+ expected.append("Hibernate: update Player set game_id=?,name=? where id=?" + System.lineSeparator());
assertEquals(expected.toString(), output.toString());
}
@@ -182,7 +179,7 @@ public class GetReferenceH2IntegrationTest {
expected.append("Hibernate: select ");
expected.append("p1_0.id,g1_0.id,g1_0.name,p1_0.name ");
expected.append("from Player p1_0 left join Game g1_0 on g1_0.id=p1_0.game_id where p1_0.id=?" + System.lineSeparator());
- expected.append("Hibernate: update Player set game_id=?, name=? where id=?" + System.lineSeparator());
+ expected.append("Hibernate: update Player set game_id=?,name=? where id=?" + System.lineSeparator());
assertEquals(expected.toString(), output.toString());
}
diff --git a/persistence-modules/pom.xml b/persistence-modules/pom.xml
index 71158d1ac8..46ac9b50f1 100644
--- a/persistence-modules/pom.xml
+++ b/persistence-modules/pom.xml
@@ -30,7 +30,7 @@
hibernate-mapping-2
-
+ hibernate-exceptions
hibernate-libraries
hibernate-jpa
diff --git a/spring-boot-modules/spring-boot-3-native/pom.xml b/spring-boot-modules/spring-boot-3-native/pom.xml
index 5382b8413c..1e93c3d8ed 100644
--- a/spring-boot-modules/spring-boot-3-native/pom.xml
+++ b/spring-boot-modules/spring-boot-3-native/pom.xml
@@ -56,10 +56,15 @@
-agentlib:native-image-agent=config-output-dir=target/native-image
-
- true
-
+
+
+ process-aot
+
+ process-aot
+
+
+
-->
diff --git a/spring-boot-modules/spring-boot-libraries-2/pom.xml b/spring-boot-modules/spring-boot-libraries-2/pom.xml
index 4409db0672..6d9401f4bc 100644
--- a/spring-boot-modules/spring-boot-libraries-2/pom.xml
+++ b/spring-boot-modules/spring-boot-libraries-2/pom.xml
@@ -11,6 +11,18 @@
1.0.0-SNAPSHOT
+
+
+
+ org.springframework.experimental
+ spring-modulith-bom
+ 0.5.1
+ import
+ pom
+
+
+
+
org.springframework.boot
@@ -87,6 +99,15 @@
2.34.0
test
+
+ org.springframework.experimental
+ spring-modulith-api
+
+
+ org.springframework.experimental
+ spring-modulith-starter-test
+ test
+
diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/Application.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/Application.java
new file mode 100644
index 0000000000..a8c3e48661
--- /dev/null
+++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/Application.java
@@ -0,0 +1,21 @@
+package com.baeldung.modulith;
+
+import com.baeldung.modulith.product.ProductService;
+import com.baeldung.modulith.product.internal.Product;
+import org.jobrunr.autoconfigure.JobRunrAutoConfiguration;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+@EnableAsync
+@SpringBootApplication
+@EnableAutoConfiguration(exclude = { JobRunrAutoConfiguration.class})
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args)
+ .getBean(ProductService.class)
+ .create(new Product("baeldung", "course", 10));
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/notification/NotificationDTO.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/notification/NotificationDTO.java
new file mode 100644
index 0000000000..a8fb346daa
--- /dev/null
+++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/notification/NotificationDTO.java
@@ -0,0 +1,39 @@
+package com.baeldung.modulith.notification;
+
+import java.util.Date;
+
+public class NotificationDTO {
+ private Date date;
+ private String format;
+ private String productName;
+
+ public NotificationDTO(Date date, String format, String productName) {
+ this.date = date;
+ this.format = format;
+ this.productName = productName;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public String getFormat() {
+ return format;
+ }
+
+ public void setFormat(String format) {
+ this.format = format;
+ }
+
+ public String getProductName() {
+ return productName;
+ }
+
+ public void setProductName(String productName) {
+ this.productName = productName;
+ }
+}
diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/notification/NotificationService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/notification/NotificationService.java
new file mode 100644
index 0000000000..7789798bbe
--- /dev/null
+++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/notification/NotificationService.java
@@ -0,0 +1,42 @@
+package com.baeldung.modulith.notification;
+
+import com.baeldung.modulith.notification.internal.Notification;
+import com.baeldung.modulith.notification.internal.NotificationType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.modulith.ApplicationModuleListener;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+@Service
+public class NotificationService {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NotificationService.class);
+
+ public void createNotification(NotificationDTO notificationDTO) {
+ Notification notification = toEntity(notificationDTO);
+ LOG.info("Received notification by module dependency for product {} in date {} by {}.", notification.getProductName()
+ , notification.getDate(), notification.getFormat());
+ }
+
+ @Async
+ @ApplicationModuleListener
+ public void notificationEvent(NotificationDTO event) {
+ Notification notification = toEntity(event);
+ LOG.info("Received notification by event for product {} in date {} by {}.", notification.getProductName()
+ , notification.getDate(), notification.getFormat());
+ }
+
+ private Notification toEntity(NotificationDTO notificationDTO) {
+ Notification notification = new Notification();
+ notification.setDate(notificationDTO.getDate());
+ if (notificationDTO.getFormat().equals("SMS")) {
+ notification.setFormat(NotificationType.SMS);
+ }
+ if (notificationDTO.getFormat().equals("EMAIL")) {
+ notification.setFormat(NotificationType.EMAIL);
+ }
+ notification.setProductName(notificationDTO.getProductName());
+ return notification;
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/notification/internal/Notification.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/notification/internal/Notification.java
new file mode 100644
index 0000000000..0b1ce85d26
--- /dev/null
+++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/notification/internal/Notification.java
@@ -0,0 +1,37 @@
+package com.baeldung.modulith.notification.internal;
+
+import java.util.Date;
+
+public class Notification {
+ private Date date;
+ private NotificationType format;
+ private String productName;
+
+ public Notification() {
+
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public NotificationType getFormat() {
+ return format;
+ }
+
+ public void setFormat(NotificationType format) {
+ this.format = format;
+ }
+
+ public String getProductName() {
+ return productName;
+ }
+
+ public void setProductName(String productName) {
+ this.productName = productName;
+ }
+}
diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/notification/internal/NotificationType.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/notification/internal/NotificationType.java
new file mode 100644
index 0000000000..45870e52b9
--- /dev/null
+++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/notification/internal/NotificationType.java
@@ -0,0 +1,5 @@
+package com.baeldung.modulith.notification.internal;
+
+public enum NotificationType {
+ EMAIL, SMS
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/product/ProductService.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/product/ProductService.java
new file mode 100644
index 0000000000..46d87fc539
--- /dev/null
+++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/product/ProductService.java
@@ -0,0 +1,26 @@
+package com.baeldung.modulith.product;
+
+import com.baeldung.modulith.notification.NotificationDTO;
+import com.baeldung.modulith.notification.NotificationService;
+import com.baeldung.modulith.product.internal.Product;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+
+@Service
+public class ProductService {
+
+ private final ApplicationEventPublisher events;
+ private final NotificationService notificationService;
+
+ public ProductService(ApplicationEventPublisher events, NotificationService notificationService) {
+ this.events = events;
+ this.notificationService = notificationService;
+ }
+
+ public void create(Product product) {
+ notificationService.createNotification(new NotificationDTO(new Date(), "SMS", product.getName()));
+ events.publishEvent(new NotificationDTO(new Date(), "SMS", product.getName()));
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/product/internal/Product.java b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/product/internal/Product.java
new file mode 100644
index 0000000000..d989906b63
--- /dev/null
+++ b/spring-boot-modules/spring-boot-libraries-2/src/main/java/com/baeldung/modulith/product/internal/Product.java
@@ -0,0 +1,38 @@
+package com.baeldung.modulith.product.internal;
+
+public class Product {
+
+ private String name;
+ private String description;
+ private int price;
+
+ public Product(String name, String description, int price) {
+ this.name = name;
+ this.description = description;
+ this.price = price;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public int getPrice() {
+ return price;
+ }
+
+ public void setPrice(int price) {
+ this.price = price;
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/modulith/ApplicationModularityUnitTest.java b/spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/modulith/ApplicationModularityUnitTest.java
new file mode 100644
index 0000000000..40d644b1e0
--- /dev/null
+++ b/spring-boot-modules/spring-boot-libraries-2/src/test/java/com/baeldung/modulith/ApplicationModularityUnitTest.java
@@ -0,0 +1,27 @@
+package com.baeldung.modulith;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.modulith.core.ApplicationModules;
+import org.springframework.modulith.docs.Documenter;
+
+class ApplicationModularityUnitTest {
+
+ ApplicationModules modules = ApplicationModules.of(Application.class);
+
+ @Test
+ void verifiesModularStructure() {
+ modules.verify();
+ }
+
+ @Test
+ void createModuleDocumentation() {
+ new Documenter(modules)
+ .writeDocumentation()
+ .writeIndividualModulesAsPlantUml();
+ }
+
+ @Test
+ void createApplicationModuleModel() {
+ modules.forEach(System.out::println);
+ }
+}
\ No newline at end of file
diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/attributes/AttributeController.java b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/attributes/AttributeController.java
new file mode 100644
index 0000000000..b7725fd992
--- /dev/null
+++ b/spring-web-modules/spring-thymeleaf-5/src/main/java/com/baeldung/thymeleaf/attributes/AttributeController.java
@@ -0,0 +1,30 @@
+package com.baeldung.thymeleaf.attributes;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@Controller
+@RequestMapping("/attributes")
+public class AttributeController {
+
+ private static final Logger logger = LoggerFactory.getLogger(AttributeController.class);
+
+ @GetMapping
+ public String show(Model model) {
+ model.addAttribute("title", "Baeldung");
+ model.addAttribute("email", "default@example.com");
+ return "attributes/index";
+ }
+
+ @PostMapping
+ public String submit(String email) {
+ logger.info("Email: {}", email);
+ return "redirect:attributes";
+ }
+
+}
diff --git a/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/attributes/index.html b/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/attributes/index.html
new file mode 100644
index 0000000000..ed55b61a8a
--- /dev/null
+++ b/spring-web-modules/spring-thymeleaf-5/src/main/resources/templates/attributes/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+ Difference Between th:text and th:value in Thymeleaf
+
+
+
+
+
+
+
+
+
\ No newline at end of file