processedNumbers = numbers.distinct()
+ .filter(nr -> nr % 2 == 0)
+ .skip(1)
+ .limit(4)
+ .map(nr -> "#" + nr)
+ .peek(nr -> System.out.println(nr));
+ String result = processedNumbers.collect(Collectors.joining(", "));
+
+ assertThat(result).isEqualTo("#2, #4, #6, #8");
+ }
+
+ @Test
+ void givenUserBuilder_thenCreateUserCorrectly() {
+ User.Builder userBuilder = User.builder();
+ userBuilder = userBuilder
+ .firstName("John")
+ .lastName("Doe")
+ .email("jd@gmail.com")
+ .username("jd_2000")
+ .id(1234L);
+
+ User user = userBuilder.build();
+
+ assertThat(user.name()).isEqualTo("John Doe");
+ }
+
+ @Test
+ void givenHtmlDocument_thenGenerateHtmlCorrectly() {
+ HtmlDocument document = new HtmlDocument()
+ .header("Principles of O.O.P.")
+ .paragraph("OOP in Java.")
+ .horizontalLine()
+ .paragraph("The main pillars of OOP are:")
+ .orderedList("Encapsulation", "Inheritance", "Abstraction", "Polymorphism");
+ String html = document.html();
+
+ assertThat(html).isEqualToIgnoringWhitespace(
+ ""
+ + "Principles of O.O.P.
"
+ + "OOP in Java.
"
+ + "
"
+ + "The main pillars of OOP are:
"
+ + ""
+ + "- Encapsulation
"
+ + "- Inheritance
"
+ + "- Abstraction
"
+ + "- Polymorphism
"
+ + "
"
+ + ""
+ );
+ }
+
+ @Test
+ void givenHtmlDocument_thenInstanceIsImmutable() {
+ HtmlDocument document = new HtmlDocument()
+ .header("Principles of O.O.P.");
+ HtmlDocument updatedDocument = document
+ .paragraph("OOP in Java.");
+
+ assertThat(document).isNotEqualTo(updatedDocument);
+ }
+
+
+ @Test
+ void givenLargeHtmlDocument_thenGenerateHtmlCorrectly() {
+ String html = new LargeHtmlDocument()
+ .head(new HtmlHeader(Type.PRIMARY, "title"))
+ .body(new HtmlDiv()
+ .append(new HtmlSpan()
+ .paragraph("learning OOP from John Doe")
+ .append(new HorizontalLine())
+ .paragraph("The pillars of OOP:")
+ )
+ .append(new HtmlList(ORDERED, "Encapsulation", "Inheritance", "Abstraction", "Polymorphism"))
+ )
+ .footer(new HtmlDiv()
+ .paragraph("trademark John Doe")
+ )
+ .html();
+
+ String expectedHtml = " title
learning OOP from John Doe
The pillars of OOP:- Encapsulation
- Inheritance
- Abstraction
- Polymorphism
";
+ assertThat(html).isEqualToIgnoringWhitespace(expectedHtml);
+ }
+}
\ No newline at end of file
diff --git a/patterns-modules/idd/pom.xml b/patterns-modules/idd/pom.xml
index 02795089e0..e08e058b92 100644
--- a/patterns-modules/idd/pom.xml
+++ b/patterns-modules/idd/pom.xml
@@ -7,16 +7,7 @@
1.0
idd
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
-
- 9
- 9
-
-
-
+
jar
diff --git a/patterns-modules/idd/src/test/java/com/baeldung/idd/HelpRequestServiceUnitTest.java b/patterns-modules/idd/src/test/java/com/baeldung/idd/HelpRequestServiceUnitTest.java
index 7bfacf8a48..52cbcaba57 100644
--- a/patterns-modules/idd/src/test/java/com/baeldung/idd/HelpRequestServiceUnitTest.java
+++ b/patterns-modules/idd/src/test/java/com/baeldung/idd/HelpRequestServiceUnitTest.java
@@ -1,7 +1,7 @@
package com.baeldung.idd;
import org.assertj.core.api.Assertions;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import java.util.List;
diff --git a/persistence-modules/pom.xml b/persistence-modules/pom.xml
index 9606da4594..d7ff51b487 100644
--- a/persistence-modules/pom.xml
+++ b/persistence-modules/pom.xml
@@ -98,7 +98,8 @@
spring-data-mongodb-reactive
spring-data-neo4j
spring-data-redis
- spring-data-rest
+
+
spring-data-rest-2
spring-data-rest-querydsl
spring-data-solr
diff --git a/persistence-modules/questdb/README.md b/persistence-modules/questdb/README.md
new file mode 100644
index 0000000000..cf4c7cbbbc
--- /dev/null
+++ b/persistence-modules/questdb/README.md
@@ -0,0 +1,2 @@
+### Relevant Articles:
+- [Introduction to QuestDB](#)
diff --git a/persistence-modules/questdb/pom.xml b/persistence-modules/questdb/pom.xml
new file mode 100644
index 0000000000..ee3db461cb
--- /dev/null
+++ b/persistence-modules/questdb/pom.xml
@@ -0,0 +1,29 @@
+
+ 4.0.0
+
+ org.baeldung
+ questdb
+ questdb
+ 0.0.1-SNAPSHOT
+
+
+ com.baeldung
+ parent-java
+ 0.0.1-SNAPSHOT
+ ../../parent-java
+
+
+
+ UTF-8
+ 7.0.0
+
+
+
+
+ org.questdb
+ questdb
+ ${questdb.version}
+
+
+
diff --git a/persistence-modules/questdb/src/main/java/com/baeldung/InsertData.java b/persistence-modules/questdb/src/main/java/com/baeldung/InsertData.java
new file mode 100644
index 0000000000..9699b7c2d0
--- /dev/null
+++ b/persistence-modules/questdb/src/main/java/com/baeldung/InsertData.java
@@ -0,0 +1,29 @@
+package com.baeldung;
+
+import io.questdb.client.Sender;
+
+
+public class InsertData {
+ static final String SENSORS_TABLE_NAME = "sensors";
+
+ public static void main(String[] args) {
+ try (Sender sender = Sender.builder().address("localhost:9009").build()) {
+ sender.table(SENSORS_TABLE_NAME)
+ .stringColumn("id", "KTC")
+ .stringColumn("name", "Kitchen temperature (Celsius)")
+ .doubleColumn("currentValue", 20)
+ .atNow();
+ sender.table(SENSORS_TABLE_NAME)
+ .stringColumn("id", "SMT")
+ .stringColumn("name", "Smart Garden temperature (Celsius)")
+ .doubleColumn("currentValue", 28.5)
+ .atNow();
+ sender.table(SENSORS_TABLE_NAME)
+ .stringColumn("id", "RM1")
+ .stringColumn("name", "Room 1")
+ .doubleColumn("currentValue", 19.5)
+ .doubleColumn("idealValue", 18.5)
+ .atNow();
+ }
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-rest/pom.xml b/persistence-modules/spring-data-rest/pom.xml
index f5601cb7ce..fa2cd033f5 100644
--- a/persistence-modules/spring-data-rest/pom.xml
+++ b/persistence-modules/spring-data-rest/pom.xml
@@ -11,9 +11,9 @@
com.baeldung
- parent-boot-2
+ parent-boot-3
0.0.1-SNAPSHOT
- ../../parent-boot-2
+ ../../parent-boot-3
@@ -42,6 +42,17 @@
spring-boot-starter-test
test
+
+ org.hibernate.orm
+ hibernate-community-dialects
+ ${hibernate-community-dialects.version}
+
+
+ io.rest-assured
+ rest-assured
+ 3.3.0
+ test
+
com.h2database
h2
@@ -64,23 +75,6 @@
${project.artifactId}
-
- com.mysema.maven
- maven-apt-plugin
- ${maven.version}
-
-
- generate-sources
-
- process
-
-
- target/generated-sources
- com.querydsl.apt.jpa.JPAAnnotationProcessor
-
-
-
-
org.springframework.boot
spring-boot-maven-plugin
@@ -91,6 +85,7 @@
com.baeldung.books.SpringDataRestApplication
1.0
+ 6.1.7.Final
\ No newline at end of file
diff --git a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/dialect/SQLiteDialect.java b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/dialect/SQLiteDialect.java
deleted file mode 100644
index 6e840eec43..0000000000
--- a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/dialect/SQLiteDialect.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package com.baeldung.books.dialect;
-
-import org.hibernate.dialect.Dialect;
-import org.hibernate.dialect.identity.IdentityColumnSupport;
-
-import java.sql.Types;
-
-public class SQLiteDialect extends Dialect {
-
- public SQLiteDialect() {
- registerColumnType(Types.BIT, "integer");
- registerColumnType(Types.TINYINT, "tinyint");
- registerColumnType(Types.SMALLINT, "smallint");
- registerColumnType(Types.INTEGER, "integer");
- registerColumnType(Types.BIGINT, "bigint");
- registerColumnType(Types.FLOAT, "float");
- registerColumnType(Types.REAL, "real");
- registerColumnType(Types.DOUBLE, "double");
- registerColumnType(Types.NUMERIC, "numeric");
- registerColumnType(Types.DECIMAL, "decimal");
- registerColumnType(Types.CHAR, "char");
- registerColumnType(Types.VARCHAR, "varchar");
- registerColumnType(Types.LONGVARCHAR, "longvarchar");
- registerColumnType(Types.DATE, "date");
- registerColumnType(Types.TIME, "time");
- registerColumnType(Types.TIMESTAMP, "timestamp");
- registerColumnType(Types.BINARY, "blob");
- registerColumnType(Types.VARBINARY, "blob");
- registerColumnType(Types.LONGVARBINARY, "blob");
- registerColumnType(Types.BLOB, "blob");
- registerColumnType(Types.CLOB, "clob");
- registerColumnType(Types.BOOLEAN, "integer");
- }
-
- public IdentityColumnSupport getIdentityColumnSupport() {
- return new SQLiteIdentityColumnSupport();
- }
-
- public boolean hasAlterTable() {
- return false;
- }
-
- public boolean dropConstraints() {
- return false;
- }
-
- public String getDropForeignKeyString() {
- return "";
- }
-
- public String getAddForeignKeyConstraintString(String constraintName, String[] foreignKey, String referencedTable, String[] primaryKey, boolean referencesPrimaryKey) {
- return "";
- }
-
- public String getAddPrimaryKeyConstraintString(String constraintName) {
- return "";
- }
-
- public String getForUpdateString() {
- return "";
- }
-
- public String getAddColumnString() {
- return "add column";
- }
-
- public boolean supportsOuterJoinForUpdate() {
- return false;
- }
-
- public boolean supportsIfExistsBeforeTableName() {
- return true;
- }
-
- public boolean supportsCascadeDelete() {
- return false;
- }
-}
diff --git a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/dialect/SQLiteIdentityColumnSupport.java b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/dialect/SQLiteIdentityColumnSupport.java
deleted file mode 100644
index 682d82c6f1..0000000000
--- a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/dialect/SQLiteIdentityColumnSupport.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.baeldung.books.dialect;
-
-import org.hibernate.MappingException;
-import org.hibernate.dialect.identity.IdentityColumnSupportImpl;
-
-public class SQLiteIdentityColumnSupport extends IdentityColumnSupportImpl {
-
- @Override
- public boolean supportsIdentityColumns() {
- return true;
- }
-
- @Override
- public String getIdentitySelectString(String table, String column, int type) throws MappingException {
- return "select last_insert_rowid()";
- }
-
- @Override
- public String getIdentityColumnString(int type) throws MappingException {
- return "integer";
- }
-}
diff --git a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Address.java b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Address.java
index 3c36db0f3c..2627c21615 100644
--- a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Address.java
+++ b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Address.java
@@ -1,11 +1,11 @@
package com.baeldung.books.models;
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.OneToOne;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.OneToOne;
@Entity
public class Address {
diff --git a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Author.java b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Author.java
index aec2e62ebf..385113d800 100644
--- a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Author.java
+++ b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Author.java
@@ -2,15 +2,15 @@ package com.baeldung.books.models;
import java.util.List;
-import javax.persistence.CascadeType;
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.JoinColumn;
-import javax.persistence.JoinTable;
-import javax.persistence.ManyToMany;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.JoinTable;
+import jakarta.persistence.ManyToMany;
@Entity
public class Author {
diff --git a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Book.java b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Book.java
index 7451b04b3b..ea3fb325c1 100644
--- a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Book.java
+++ b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Book.java
@@ -2,15 +2,15 @@ package com.baeldung.books.models;
import java.util.List;
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.FetchType;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.JoinColumn;
-import javax.persistence.ManyToMany;
-import javax.persistence.ManyToOne;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToMany;
+import jakarta.persistence.ManyToOne;
@Entity
public class Book {
diff --git a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Library.java b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Library.java
index 5f95169a9b..28a54dbd33 100644
--- a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Library.java
+++ b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Library.java
@@ -2,14 +2,14 @@ package com.baeldung.books.models;
import java.util.List;
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.JoinColumn;
-import javax.persistence.OneToMany;
-import javax.persistence.OneToOne;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.OneToOne;
import org.springframework.data.rest.core.annotation.RestResource;
diff --git a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Subject.java b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Subject.java
index 11a4425fdd..28d16f5054 100644
--- a/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Subject.java
+++ b/persistence-modules/spring-data-rest/src/main/java/com/baeldung/books/models/Subject.java
@@ -1,10 +1,10 @@
package com.baeldung.books.models;
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
@Entity
public class Subject {
diff --git a/persistence-modules/spring-data-rest/src/main/resources/persistence-sqlite.properties b/persistence-modules/spring-data-rest/src/main/resources/persistence-sqlite.properties
index b6b5f4e4d6..e570322a82 100644
--- a/persistence-modules/spring-data-rest/src/main/resources/persistence-sqlite.properties
+++ b/persistence-modules/spring-data-rest/src/main/resources/persistence-sqlite.properties
@@ -2,6 +2,6 @@ driverClassName=org.sqlite.JDBC
url=jdbc:sqlite:memory:myDb?cache=shared
username=sa
password=sa
-hibernate.dialect=com.baeldung.dialect.SQLiteDialect
+spring.jpa.database-platform=org.hibernate.community.dialect.SQLiteDialect
hibernate.hbm2ddl.auto=create-drop
hibernate.show_sql=true
diff --git a/pom.xml b/pom.xml
index 6f159ac8a7..8e23a6e94f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -330,59 +330,35 @@
parent-spring-5
parent-java
-
- azure
checker-plugin
-
core-java-modules
-
couchbase
-
gradle-modules/gradle/maven-to-gradle
-
-
apache-httpclient
apache-httpclient4
-
java-jdi
- java-websocket
+ jetbrains
jhipster-5
-
jmh
-
- kubernetes-modules
-
language-interop
libraries-3
-
libraries-data-db
-
logging-modules
lombok-modules
-
maven-modules
- messaging-modules
-
microservices-modules
muleesb
-
- netflix-modules
-
osgi
-
-
persistence-modules
-
- vavr-modules
web-modules
@@ -428,7 +404,6 @@
parent-spring-5
parent-java
- spf4j
spring-4
spring-aop
@@ -436,14 +411,11 @@
spring-boot-modules
spring-cloud-modules
- spring-di
- spring-di-2
- spring-ejb-modules
+
spring-exceptions
spring-integration
spring-jenkins-pipeline
- spring-jinq
spring-katharsis
spring-mobile
spring-remoting-modules
@@ -520,10 +492,9 @@
libraries-5
libraries-6
spring-boot-modules/spring-boot-react
- spring-ejb-modules/ejb-beans
vaadin
- vavr-modules
+
@@ -559,8 +530,6 @@
parent-spring-5
parent-java
-
- azure
checker-plugin
@@ -571,43 +540,24 @@
gradle-modules/gradle/maven-to-gradle
-
apache-httpclient
apache-httpclient4
-
java-jdi
- java-websocket
jhipster-5
jmh
-
- kubernetes-modules
-
language-interop
libraries-3
-
libraries-data-db
-
logging-modules
lombok-modules
-
maven-modules
-
- messaging-modules
-
microservices-modules
muleesb
- netflix-modules
-
osgi
-
-
-
persistence-modules
-
- vavr-modules
web-modules
@@ -645,21 +595,17 @@
parent-spring-5
parent-java
-
- spf4j
spring-4
spring-bom
spring-boot-modules
spring-cloud-modules
- spring-di
- spring-di-2
- spring-ejb-modules
+
spring-exceptions
spring-integration
spring-jenkins-pipeline
- spring-jinq
+
spring-katharsis
spring-mobile
spring-remoting-modules
@@ -728,9 +674,7 @@
libraries-5
libraries-6
spring-boot-modules/spring-boot-react
- spring-ejb-modules/ejb-beans
vaadin
- vavr-modules
@@ -796,9 +740,20 @@
+ spring-ejb-modules
+ spring-di
+ spring-di-2
+ spring-jinq
+ vavr-modules
+ java-websocket
+ azure
+ netflix-modules
+ spf4j
+
spring-jersey
jersey
jaxb
+
javafx
spring-batch
spring-boot-rest
@@ -884,7 +839,7 @@
drools
guava-modules
apache-httpclient-2
- kubernetes-modules/kubernetes-spring
+ kubernetes-modules
libraries-concurrency
libraries-testing
maven-modules/compiler-plugin-java-9
@@ -904,6 +859,7 @@
spring-swagger-codegen/custom-validations-opeanpi-codegen
testing-modules/testing-assertions
persistence-modules/fauna
+ persistence-modules/spring-data-rest
rule-engines-modules
@@ -933,7 +889,7 @@
asm
atomikos
atomix
-
+
bazel
code-generation
@@ -942,7 +898,7 @@
disruptor
dozer
dubbo
- feign
+
google-cloud
graphql-modules
grpc
@@ -1021,9 +977,10 @@
xstream
webrtc
persistence-modules/java-mongodb
- messaging-modules/spring-apache-camel
+ messaging-modules
spring-boot-modules/spring-boot-redis
spring-security-modules/spring-security-saml2
+ persistence-modules/questdb
@@ -1057,9 +1014,20 @@
+ spring-ejb-modules
+ spring-di
+ spring-di-2
+ spring-jinq
+ vavr-modules
+ java-websocket
+ azure
+ netflix-modules
+ spf4j
+
spring-jersey
jersey
jaxb
+
javafx
spring-batch
spring-boot-rest
@@ -1143,7 +1111,7 @@
drools
guava-modules
apache-httpclient-2
- kubernetes-modules/kubernetes-spring
+ kubernetes-modules
libraries-concurrency
libraries-testing
maven-modules/compiler-plugin-java-9
@@ -1163,6 +1131,7 @@
spring-swagger-codegen/custom-validations-opeanpi-codegen
testing-modules/testing-assertions
persistence-modules/fauna
+ persistence-modules/spring-data-rest
rule-engines-modules
@@ -1191,7 +1160,7 @@
asm
atomikos
atomix
-
+
bazel
code-generation
@@ -1201,7 +1170,7 @@
dozer
dubbo
- feign
+
google-cloud
graphql-modules
grpc
@@ -1282,9 +1251,10 @@
webrtc
persistence-modules/java-mongodb
libraries-2
- messaging-modules/spring-apache-camel
+ messaging-modules
spring-boot-modules/spring-boot-redis
spring-security-modules/spring-security-saml2
+ persistence-modules/questdb
diff --git a/spf4j/spf4j-aspects-app/pom.xml b/spf4j/spf4j-aspects-app/pom.xml
index 09ca41ea47..3eccdd879a 100644
--- a/spf4j/spf4j-aspects-app/pom.xml
+++ b/spf4j/spf4j-aspects-app/pom.xml
@@ -55,11 +55,6 @@
org.apache.maven.plugins
maven-compiler-plugin
- ${compiler.plugin.version}
-
- ${java.version}
- ${java.version}
-
org.apache.maven.plugins
@@ -98,7 +93,6 @@
8.9.0
- 3.8.0
3.1.1
diff --git a/spf4j/spf4j-core-app/pom.xml b/spf4j/spf4j-core-app/pom.xml
index 2f7f3745f1..20251860aa 100644
--- a/spf4j/spf4j-core-app/pom.xml
+++ b/spf4j/spf4j-core-app/pom.xml
@@ -61,11 +61,6 @@
org.apache.maven.plugins
maven-compiler-plugin
- ${compiler.plugin.version}
-
- ${java.version}
- ${java.version}
-
org.apache.maven.plugins
@@ -104,7 +99,6 @@
8.9.0
- 3.8.0
3.1.1
diff --git a/spring-batch/pom.xml b/spring-batch/pom.xml
index 32126fec9b..e9d3afa376 100644
--- a/spring-batch/pom.xml
+++ b/spring-batch/pom.xml
@@ -28,13 +28,13 @@
javax.xml.bind
jaxb-api
${jaxb.version}
- runtime
+
org.glassfish.jaxb
jaxb-runtime
${jaxb.version}
- runtime
+
diff --git a/spring-boot-modules/spring-boot-3/pom.xml b/spring-boot-modules/spring-boot-3/pom.xml
index cc8e7e1426..685df233ba 100644
--- a/spring-boot-modules/spring-boot-3/pom.xml
+++ b/spring-boot-modules/spring-boot-3/pom.xml
@@ -124,6 +124,8 @@
1.5.2.Final
2.0.0
3.0.0-M7
+ com.baeldung.sample.TodoApplication
+
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/QueryService.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/QueryService.java
new file mode 100644
index 0000000000..4c1e73e530
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/QueryService.java
@@ -0,0 +1,42 @@
+package com.baeldung.recordswithjpa;
+
+import com.baeldung.recordswithjpa.entity.Book;
+import com.baeldung.recordswithjpa.records.BookRecord;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+import jakarta.persistence.Query;
+import jakarta.persistence.TypedQuery;
+import jakarta.persistence.criteria.CriteriaBuilder;
+import jakarta.persistence.criteria.CriteriaQuery;
+import jakarta.persistence.criteria.Root;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class QueryService {
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ public List findAllBooks() {
+ CriteriaBuilder cb = entityManager.getCriteriaBuilder();
+ CriteriaQuery query = cb.createQuery(BookRecord.class);
+ Root root = query.from(Book.class);
+ query.select(cb
+ .construct(BookRecord.class, root.get("id"), root.get("title"), root.get("author"), root.get("isbn")));
+ return entityManager.createQuery(query).getResultList();
+ }
+
+ public BookRecord findBookById(Long id) {
+ TypedQuery query = entityManager
+ .createQuery("SELECT new com.baeldung.recordswithjpa.records.BookRecord(b.id, b.title, b.author, b.isbn) " +
+ "FROM Book b WHERE b.id = :id", BookRecord.class);
+ query.setParameter("id", id);
+ return query.getSingleResult();
+ }
+
+ public List findAllBooksUsingMapping() {
+ Query query = entityManager.createNativeQuery("SELECT * FROM book", "BookRecordMapping");
+ return query.getResultList();
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/RecordsAsJpaApplication.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/RecordsAsJpaApplication.java
new file mode 100644
index 0000000000..d6eb1edec1
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/RecordsAsJpaApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.recordswithjpa;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class RecordsAsJpaApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(RecordsAsJpaApplication.class, args);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/entity/Book.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/entity/Book.java
new file mode 100644
index 0000000000..9ea982e323
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/entity/Book.java
@@ -0,0 +1,70 @@
+package com.baeldung.recordswithjpa.entity;
+
+import com.baeldung.recordswithjpa.records.BookRecord;
+import jakarta.persistence.*;
+
+@SqlResultSetMapping(
+ name = "BookRecordMapping",
+ classes = @ConstructorResult(
+ targetClass = BookRecord.class,
+ columns = {
+ @ColumnResult(name = "id", type = Long.class),
+ @ColumnResult(name = "title", type = String.class),
+ @ColumnResult(name = "author", type = String.class),
+ @ColumnResult(name = "isbn", type = String.class)
+ }
+ )
+)
+@Entity
+@Table(name = "book")
+public class Book {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+ private String title;
+ private String author;
+ private String isbn;
+
+ public Book() {
+ }
+
+ public Book(Long id, String title, String author, String isbn) {
+ this.id = id;
+ this.title = title;
+ this.author = author;
+ this.isbn = isbn;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public String getIsbn() {
+ return isbn;
+ }
+
+ public void setIsbn(String isbn) {
+ this.isbn = isbn;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/BookRecord.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/BookRecord.java
new file mode 100644
index 0000000000..96968575d9
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/BookRecord.java
@@ -0,0 +1,4 @@
+package com.baeldung.recordswithjpa.records;
+
+public record BookRecord(Long id, String title, String author, String isbn) {
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/CustomBookRecord.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/CustomBookRecord.java
new file mode 100644
index 0000000000..35e9be9513
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/records/CustomBookRecord.java
@@ -0,0 +1,4 @@
+package com.baeldung.recordswithjpa.records;
+
+public record CustomBookRecord(Long id, String title) {
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/BookRepository.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/BookRepository.java
new file mode 100644
index 0000000000..4ef5f17296
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/BookRepository.java
@@ -0,0 +1,17 @@
+package com.baeldung.recordswithjpa.repository;
+
+import com.baeldung.recordswithjpa.entity.Book;
+import com.baeldung.recordswithjpa.records.BookRecord;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.data.repository.query.Param;
+
+import java.util.List;
+
+public interface BookRepository extends CrudRepository {
+ List findBookByAuthor(String author);
+
+ @Query("SELECT new com.baeldung.recordswithjpa.records.BookRecord(b.id, b.title, b.author, b.isbn) " +
+ "FROM Book b WHERE b.id = :id")
+ BookRecord findBookById(@Param("id") Long id);
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepository.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepository.java
new file mode 100644
index 0000000000..bb8002d70d
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepository.java
@@ -0,0 +1,9 @@
+package com.baeldung.recordswithjpa.repository;
+
+import com.baeldung.recordswithjpa.records.CustomBookRecord;
+
+import java.util.List;
+
+public interface CustomBookRepository {
+ List findAllBooks();
+}
diff --git a/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryImpl.java b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryImpl.java
new file mode 100644
index 0000000000..8d420a9874
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/main/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryImpl.java
@@ -0,0 +1,20 @@
+package com.baeldung.recordswithjpa.repository;
+
+import com.baeldung.recordswithjpa.records.CustomBookRecord;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public class CustomBookRepositoryImpl implements CustomBookRepository {
+ private final JdbcTemplate jdbcTemplate;
+
+ public CustomBookRepositoryImpl(JdbcTemplate jdbcTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ }
+
+ public List findAllBooks() {
+ return jdbcTemplate.query("SELECT id, title FROM book", (rs, rowNum) -> new CustomBookRecord(rs.getLong("id"), rs.getString("title")));
+ }
+}
diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/QueryServiceIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/QueryServiceIntegrationTest.java
new file mode 100644
index 0000000000..011895e7fa
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/QueryServiceIntegrationTest.java
@@ -0,0 +1,39 @@
+package com.baeldung.recordswithjpa;
+
+import com.baeldung.recordswithjpa.entity.Book;
+import com.baeldung.recordswithjpa.records.BookRecord;
+import com.baeldung.recordswithjpa.repository.BookRepository;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class QueryServiceIntegrationTest extends RecordsAsJpaIntegrationTest {
+
+ @Autowired
+ private QueryService queryService;
+
+
+ @Test
+ void findAllBooks() {
+ List allBooks = queryService.findAllBooks();
+ assertEquals(3, allBooks.size());
+ }
+
+ @Test
+ void findBookById() {
+ BookRecord bookById = queryService.findBookById(1L);
+ assertEquals("The Lord of the Rings", bookById.title());
+ }
+
+ @Test
+ void findAllBooksUsingMapping() {
+ List allBooksUsingMapping = queryService.findAllBooksUsingMapping();
+ assertEquals(3, allBooksUsingMapping.size());
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/RecordsAsJpaIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/RecordsAsJpaIntegrationTest.java
new file mode 100644
index 0000000000..f0869dad48
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/RecordsAsJpaIntegrationTest.java
@@ -0,0 +1,30 @@
+package com.baeldung.recordswithjpa;
+
+import com.baeldung.recordswithjpa.entity.Book;
+import com.baeldung.recordswithjpa.repository.BookRepository;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+public class RecordsAsJpaIntegrationTest {
+ @Autowired
+ protected BookRepository bookRepository;
+
+ @BeforeEach
+ void setUp() {
+ Book book = new Book(1L,"The Lord of the Rings", "J.R.R. Tolkien", "978-0544003415");
+ Book book2 = new Book(2L,"The Hobbit", "J.R.R. Tolkien", "978-0547928227");
+ Book book3 = new Book(3L,"Harry Potter and the Philosopher's Stone", "J.K. Rowling", "978-0747532699");
+
+ bookRepository.save(book);
+ bookRepository.save(book2);
+ bookRepository.save(book3);
+ }
+
+ @AfterEach
+ void tearDown() {
+ bookRepository.deleteAll();
+ }
+}
diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/BookRepositoryIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/BookRepositoryIntegrationTest.java
new file mode 100644
index 0000000000..9173fea269
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/BookRepositoryIntegrationTest.java
@@ -0,0 +1,19 @@
+package com.baeldung.recordswithjpa.repository;
+
+import com.baeldung.recordswithjpa.RecordsAsJpaIntegrationTest;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class BookRepositoryIntegrationTest extends RecordsAsJpaIntegrationTest {
+
+ @Test
+ void findBookByAuthor() {
+ assertEquals(2, bookRepository.findBookByAuthor("J.R.R. Tolkien").size());
+ }
+
+ @Test
+ void findBookById() {
+ assertEquals("The Lord of the Rings", bookRepository.findBookById(1L).title());
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryIntegrationTest.java b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryIntegrationTest.java
new file mode 100644
index 0000000000..866645429a
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3/src/test/java/com/baeldung/recordswithjpa/repository/CustomBookRepositoryIntegrationTest.java
@@ -0,0 +1,23 @@
+package com.baeldung.recordswithjpa.repository;
+
+import com.baeldung.recordswithjpa.RecordsAsJpaIntegrationTest;
+import com.baeldung.recordswithjpa.records.CustomBookRecord;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class CustomBookRepositoryIntegrationTest extends RecordsAsJpaIntegrationTest {
+
+ @Autowired
+ private CustomBookRepository customBookRepository;
+
+ @Test
+ void findAllBooks() {
+ List allBooks = customBookRepository.findAllBooks();
+ assertEquals(3, allBooks.size());
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/SpringDocExampleApplication.java b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/SpringDocExampleApplication.java
new file mode 100644
index 0000000000..3ae057630d
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/SpringDocExampleApplication.java
@@ -0,0 +1,17 @@
+package com.baeldung.springdoc.demo;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+import com.baeldung.springdoc.demo.config.SpringDocSwaggerConfig;
+
+@SpringBootApplication
+public class SpringDocExampleApplication {
+
+ public static void main(String[] args) {
+ SpringApplication application = new SpringApplication(SpringDocExampleApplication.class);
+ //Note: SpringDocExampleApplication is the name of your main class
+ application.addListeners(new SpringDocSwaggerConfig());
+ application.run(args);
+ }
+}
diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/SpringFoxExampleApplication.java b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/SpringFoxExampleApplication.java
new file mode 100644
index 0000000000..c6106cc95d
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/SpringFoxExampleApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.springdoc.demo;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SpringFoxExampleApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SpringFoxExampleApplication.class, args);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/config/SpringDocSwaggerConfig.java b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/config/SpringDocSwaggerConfig.java
new file mode 100644
index 0000000000..5836235445
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/config/SpringDocSwaggerConfig.java
@@ -0,0 +1,25 @@
+package com.baeldung.springdoc.demo.config;
+
+import java.util.Properties;
+
+import org.springframework.boot.context.event.ApplicationPreparedEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.PropertiesPropertySource;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SpringDocSwaggerConfig implements ApplicationListener {
+
+ @Override
+ public void onApplicationEvent(final ApplicationPreparedEvent event) {
+ ConfigurableEnvironment environment = event.getApplicationContext().getEnvironment();
+ Properties props = new Properties();
+ props.put("springdoc.swagger-ui.path", swaggerPath());
+ environment.getPropertySources().addFirst(new PropertiesPropertySource("programmatically", props));
+ }
+
+ private String swaggerPath() {
+ return "/myproject"; // TODO: implement your logic here.
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/config/SpringFoxSwaggerConfig.java b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/config/SpringFoxSwaggerConfig.java
new file mode 100644
index 0000000000..e07ca5c2a1
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/config/SpringFoxSwaggerConfig.java
@@ -0,0 +1,28 @@
+package com.baeldung.springdoc.demo.config;
+
+import java.util.ArrayList;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+
+@Configuration
+public class SpringFoxSwaggerConfig {
+
+ @Bean
+ public Docket productApi() {
+ return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.any())
+ .paths(PathSelectors.any()).build().apiInfo(metaInfo());
+ }
+
+ private ApiInfo metaInfo() {
+
+ return new ApiInfo("Sample API REST", "API REST", "1.0", "Terms of Service", null, "Apache License Version 2.0",
+ "https://www.apache.org/licesen.html", new ArrayList<>());
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/controller/SwaggerController.java b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/controller/SwaggerController.java
new file mode 100644
index 0000000000..79c35e025e
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/controller/SwaggerController.java
@@ -0,0 +1,13 @@
+package com.baeldung.springdoc.demo.controller;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@Controller
+public class SwaggerController {
+
+ @RequestMapping("/myproject")
+ public String getRedirectUrl() {
+ return "redirect:swagger-ui.html";
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/controller/TopicsController.java b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/controller/TopicsController.java
new file mode 100644
index 0000000000..dee825788d
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/controller/TopicsController.java
@@ -0,0 +1,26 @@
+package com.baeldung.springdoc.demo.controller;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.springdoc.demo.model.Topic;
+import com.baeldung.springdoc.demo.service.TopicService;
+
+
+@RestController
+public class TopicsController {
+
+ @Autowired
+ TopicService topicService;
+
+ @GetMapping(value = "/topics")
+ public ResponseEntity> getAllTopics() {
+ return new ResponseEntity<>(topicService.getAlllTopics(), HttpStatus.OK);
+ }
+}
diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/model/Topic.java b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/model/Topic.java
new file mode 100644
index 0000000000..0e4417b64f
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/model/Topic.java
@@ -0,0 +1,26 @@
+package com.baeldung.springdoc.demo.model;
+
+public class Topic {
+
+ Integer id;
+ String name;
+
+ public Topic(Integer id, String name) {
+ super();
+ this.id = id;
+ this.name = name;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+ public void setId(Integer id) {
+ this.id = id;
+ }
+ public String getName() {
+ return name;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/service/TopicService.java b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/service/TopicService.java
new file mode 100644
index 0000000000..a468d2915b
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger-2/src/main/java/com/baeldung/springdoc/demo/service/TopicService.java
@@ -0,0 +1,26 @@
+package com.baeldung.springdoc.demo.service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.stereotype.Service;
+
+import com.baeldung.springdoc.demo.model.Topic;
+
+@Service
+public class TopicService {
+
+ private List topicsList;
+
+ public TopicService(){
+ this.topicsList = new ArrayList() {{
+ add(new Topic(1, "Topic1"));
+ add(new Topic(2, "Topic2"));
+ add(new Topic(3, "Topic3"));
+ }};
+ }
+
+ public List getAlllTopics(){
+ return topicsList;
+ }
+}
diff --git a/spring-boot-modules/spring-boot-swagger-2/src/main/resources/application.properties b/spring-boot-modules/spring-boot-swagger-2/src/main/resources/application.properties
index 03302ebb1c..901f0a6cc3 100644
--- a/spring-boot-modules/spring-boot-swagger-2/src/main/resources/application.properties
+++ b/spring-boot-modules/spring-boot-swagger-2/src/main/resources/application.properties
@@ -1,2 +1,7 @@
springdoc.api-docs.enabled=false
springdoc.swagger-ui.url=/api_3.yaml
+
+# Properties for custom Springdoc swagger-ui url
+
+#springdoc.swagger-ui.disable-swagger-default-url=true
+#springdoc.swagger-ui.path=/myproject
\ No newline at end of file
diff --git a/spring-di-2/pom.xml b/spring-di-2/pom.xml
index 1207506d17..69333c74f1 100644
--- a/spring-di-2/pom.xml
+++ b/spring-di-2/pom.xml
@@ -85,7 +85,7 @@
2.6.1
- 1.11
+ 1.14.0
1
2.17.1
diff --git a/spring-di/pom.xml b/spring-di/pom.xml
index af0601deb6..cf3703096c 100644
--- a/spring-di/pom.xml
+++ b/spring-di/pom.xml
@@ -149,6 +149,7 @@
1.5.2.RELEASE
1.10.19
1.9.5
+ 3.3.2
\ No newline at end of file
diff --git a/spring-ejb-modules/wildfly/pom.xml b/spring-ejb-modules/wildfly/pom.xml
index c73a1f128d..f122e99001 100644
--- a/spring-ejb-modules/wildfly/pom.xml
+++ b/spring-ejb-modules/wildfly/pom.xml
@@ -85,8 +85,6 @@
- 1.8
- 1.8
7.0
10.1.0.Final
5.2.3.Final
diff --git a/spring-ejb-modules/wildfly/widlfly-web/pom.xml b/spring-ejb-modules/wildfly/widlfly-web/pom.xml
index fb8a7678af..46c3f7d0bc 100644
--- a/spring-ejb-modules/wildfly/widlfly-web/pom.xml
+++ b/spring-ejb-modules/wildfly/widlfly-web/pom.xml
@@ -41,4 +41,7 @@
+
+ 3.3.2
+
\ No newline at end of file
diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/BookConsumer.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/BookConsumer.java
new file mode 100644
index 0000000000..77c7dc2e91
--- /dev/null
+++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/BookConsumer.java
@@ -0,0 +1,26 @@
+package com.baeldung.spring.kafka.multiplelisteners;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.stereotype.Service;
+
+@Service
+public class BookConsumer {
+ private static final Logger logger = LoggerFactory.getLogger(BookConsumer.class);
+
+ @KafkaListener(topics = "books", groupId = "books-content-search")
+ public void bookContentSearchConsumer(BookEvent event) {
+ logger.info("Books event received for full-text search indexing => {}", event);
+ }
+
+ @KafkaListener(topics = "books", groupId = "books-price-index")
+ public void bookPriceIndexerConsumer(BookEvent event) {
+ logger.info("Books event received for price indexing => {}", event);
+ }
+
+ @KafkaListener(topics = "books", groupId = "book-notification-consumer", concurrency = "2")
+ public void bookNotificationConsumer(BookEvent event) {
+ logger.info("Books event received for notification => {}", event);
+ }
+}
diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/BookEvent.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/BookEvent.java
new file mode 100644
index 0000000000..11b13f120d
--- /dev/null
+++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/BookEvent.java
@@ -0,0 +1,15 @@
+package com.baeldung.spring.kafka.multiplelisteners;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class BookEvent {
+
+ private String title;
+ private String description;
+ private Double price;
+}
diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaConsumerConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaConsumerConfig.java
new file mode 100644
index 0000000000..a6e0a91425
--- /dev/null
+++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaConsumerConfig.java
@@ -0,0 +1,64 @@
+package com.baeldung.spring.kafka.multiplelisteners;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.kafka.clients.consumer.ConsumerConfig;
+import org.apache.kafka.common.serialization.StringDeserializer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.annotation.EnableKafka;
+import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
+import org.springframework.kafka.core.ConsumerFactory;
+import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
+import org.springframework.kafka.listener.DefaultErrorHandler;
+import org.springframework.kafka.support.serializer.JsonDeserializer;
+import org.springframework.util.backoff.BackOff;
+import org.springframework.util.backoff.FixedBackOff;
+
+@EnableKafka
+@Configuration
+public class KafkaConsumerConfig {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(KafkaConsumerConfig.class);
+
+ @Value(value = "${spring.kafka.bootstrap-servers}")
+ private String bootstrapAddress;
+
+ @Value(value = "${kafka.backoff.interval}")
+ private Long interval;
+
+ @Value(value = "${kafka.backoff.max_failure}")
+ private Long maxAttempts;
+
+ public ConsumerFactory consumerFactory() {
+ Map props = new HashMap<>();
+ props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress);
+ props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
+ props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
+ props.put(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG, "20971520");
+ props.put(ConsumerConfig.FETCH_MAX_BYTES_CONFIG, "20971520");
+ props.put(JsonDeserializer.TRUSTED_PACKAGES, "*");
+ props.put(JsonDeserializer.TYPE_MAPPINGS, "bookEvent:com.baeldung.spring.kafka.multiplelisteners.BookEvent");
+
+ return new DefaultKafkaConsumerFactory<>(props);
+ }
+
+ @Bean
+ public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() {
+ ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>();
+ factory.setConsumerFactory(consumerFactory());
+ factory.setCommonErrorHandler(errorHandler());
+ return factory;
+ }
+
+ @Bean
+ public DefaultErrorHandler errorHandler() {
+ BackOff fixedBackOff = new FixedBackOff(interval, maxAttempts);
+ return new DefaultErrorHandler((consumerRecord, e) -> LOGGER.error(String.format("consumed record %s because this exception was thrown", consumerRecord.toString())), fixedBackOff);
+ }
+
+}
diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaProducerConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaProducerConfig.java
new file mode 100644
index 0000000000..35204428a0
--- /dev/null
+++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaProducerConfig.java
@@ -0,0 +1,54 @@
+package com.baeldung.spring.kafka.multiplelisteners;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.kafka.clients.producer.ProducerConfig;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.core.DefaultKafkaProducerFactory;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.kafka.core.ProducerFactory;
+import org.springframework.kafka.support.serializer.JsonSerializer;
+
+@Configuration
+public class KafkaProducerConfig {
+
+ @Value(value = "${spring.kafka.bootstrap-servers}")
+ private String bootstrapAddress;
+
+ @Bean
+ public ProducerFactory producerFactory() {
+ Map configProps = new HashMap<>();
+ configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress);
+ configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+ configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+ configProps.put(ProducerConfig.MAX_REQUEST_SIZE_CONFIG, "20971520");
+
+ return new DefaultKafkaProducerFactory<>(configProps);
+ }
+
+ @Bean
+ public KafkaTemplate kafkaTemplate() {
+ return new KafkaTemplate<>(producerFactory());
+ }
+
+ @Bean
+ public ProducerFactory bookProducerFactory() {
+ Map configProps = new HashMap<>();
+ configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress);
+ configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+ configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
+ configProps.put(JsonSerializer.TYPE_MAPPINGS, "bookEvent:com.baeldung.spring.kafka.multiplelisteners.BookEvent");
+
+ return new DefaultKafkaProducerFactory<>(configProps);
+ }
+
+ @Bean
+ public KafkaTemplate bookKafkaTemplate() {
+ return new KafkaTemplate<>(bookProducerFactory());
+ }
+
+}
diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaTopicConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaTopicConfig.java
new file mode 100644
index 0000000000..5bc0a966b5
--- /dev/null
+++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/KafkaTopicConfig.java
@@ -0,0 +1,33 @@
+package com.baeldung.spring.kafka.multiplelisteners;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.kafka.clients.admin.AdminClientConfig;
+import org.apache.kafka.clients.admin.NewTopic;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.core.KafkaAdmin;
+
+@Configuration
+public class KafkaTopicConfig {
+
+ @Value(value = "${spring.kafka.bootstrap-servers}")
+ private String bootstrapAddress;
+
+ @Value(value = "${multiple-listeners.books.topic.name}")
+ private String booksTopicName;
+
+ @Bean
+ public KafkaAdmin kafkaAdmin() {
+ Map configs = new HashMap<>();
+ configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress);
+ return new KafkaAdmin(configs);
+ }
+
+ @Bean
+ public NewTopic booksTopic() {
+ return new NewTopic(booksTopicName, 1, (short) 1);
+ }
+}
diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/MultipleListenersApplicationKafkaApp.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/MultipleListenersApplicationKafkaApp.java
new file mode 100644
index 0000000000..c8a2f6e689
--- /dev/null
+++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/multiplelisteners/MultipleListenersApplicationKafkaApp.java
@@ -0,0 +1,14 @@
+package com.baeldung.spring.kafka.multiplelisteners;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Import;
+
+@SpringBootApplication
+@Import(value = { KafkaTopicConfig.class, KafkaConsumerConfig.class, KafkaProducerConfig.class })
+public class MultipleListenersApplicationKafkaApp {
+
+ public static void main(String[] args) {
+ SpringApplication.run(MultipleListenersApplicationKafkaApp.class, args);
+ }
+}
diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Farewell.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/Farewell.java
similarity index 94%
rename from spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Farewell.java
rename to spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/Farewell.java
index bbff315ad2..519d847aab 100644
--- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Farewell.java
+++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/Farewell.java
@@ -1,4 +1,4 @@
-package com.baeldung.spring.kafka;
+package com.baeldung.spring.kafka.retryable;
public class Farewell {
diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Greeting.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/Greeting.java
similarity index 92%
rename from spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Greeting.java
rename to spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/Greeting.java
index b4633e802a..79abeda34e 100644
--- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/Greeting.java
+++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/Greeting.java
@@ -1,4 +1,4 @@
-package com.baeldung.spring.kafka;
+package com.baeldung.spring.kafka.retryable;
public class Greeting {
diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaConsumerConfig.java
similarity index 98%
rename from spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java
rename to spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaConsumerConfig.java
index 463d3209ea..cf4b29137e 100644
--- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaConsumerConfig.java
+++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaConsumerConfig.java
@@ -1,6 +1,5 @@
-package com.baeldung.spring.kafka;
+package com.baeldung.spring.kafka.retryable;
-import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Map;
diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaProducerConfig.java
similarity index 94%
rename from spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java
rename to spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaProducerConfig.java
index da8b2bd1a6..90dcb2ccf9 100644
--- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaProducerConfig.java
+++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaProducerConfig.java
@@ -1,4 +1,4 @@
-package com.baeldung.spring.kafka;
+package com.baeldung.spring.kafka.retryable;
import java.util.HashMap;
import java.util.Map;
@@ -55,7 +55,7 @@ public class KafkaProducerConfig {
configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress);
configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
- configProps.put(JsonSerializer.TYPE_MAPPINGS, "greeting:com.baeldung.spring.kafka.Greeting, farewell:com.baeldung.spring.kafka.Farewell");
+ configProps.put(JsonSerializer.TYPE_MAPPINGS, "greeting:com.baeldung.spring.kafka.retrayable.Greeting, farewell:com.baeldung.spring.kafka.retrayable.Farewell");
return new DefaultKafkaProducerFactory<>(configProps);
}
diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaTopicConfig.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaTopicConfig.java
similarity index 97%
rename from spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaTopicConfig.java
rename to spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaTopicConfig.java
index 6a20915699..3b4c2d9928 100644
--- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/KafkaTopicConfig.java
+++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/KafkaTopicConfig.java
@@ -1,4 +1,4 @@
-package com.baeldung.spring.kafka;
+package com.baeldung.spring.kafka.retryable;
import java.util.HashMap;
import java.util.Map;
diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/MultiTypeKafkaListener.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/MultiTypeKafkaListener.java
similarity index 95%
rename from spring-kafka-2/src/main/java/com/baeldung/spring/kafka/MultiTypeKafkaListener.java
rename to spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/MultiTypeKafkaListener.java
index 6c4d78171b..441e564176 100644
--- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/MultiTypeKafkaListener.java
+++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/MultiTypeKafkaListener.java
@@ -1,4 +1,4 @@
-package com.baeldung.spring.kafka;
+package com.baeldung.spring.kafka.retryable;
import org.springframework.kafka.annotation.KafkaHandler;
import org.springframework.kafka.annotation.KafkaListener;
diff --git a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/RetryableApplicationKafkaApp.java b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/RetryableApplicationKafkaApp.java
similarity index 91%
rename from spring-kafka-2/src/main/java/com/baeldung/spring/kafka/RetryableApplicationKafkaApp.java
rename to spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/RetryableApplicationKafkaApp.java
index e43207829a..458ebac124 100644
--- a/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/RetryableApplicationKafkaApp.java
+++ b/spring-kafka-2/src/main/java/com/baeldung/spring/kafka/retryable/RetryableApplicationKafkaApp.java
@@ -1,4 +1,4 @@
-package com.baeldung.spring.kafka;
+package com.baeldung.spring.kafka.retryable;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
diff --git a/spring-kafka-2/src/main/resources/application.properties b/spring-kafka-2/src/main/resources/application.properties
index 691b6f55b7..4725ace2d9 100644
--- a/spring-kafka-2/src/main/resources/application.properties
+++ b/spring-kafka-2/src/main/resources/application.properties
@@ -16,5 +16,7 @@ monitor.kafka.consumer.groupid.simulate=baeldungGrpSimulate
test.topic=testtopic1
kafka.backoff.interval=9000
kafka.backoff.max_failure=5
+# multiple listeners properties
+multiple-listeners.books.topic.name=books
diff --git a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multiplelisteners/KafkaMultipleListenersIntegrationTest.java b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multiplelisteners/KafkaMultipleListenersIntegrationTest.java
new file mode 100644
index 0000000000..b6634ec7ed
--- /dev/null
+++ b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/multiplelisteners/KafkaMultipleListenersIntegrationTest.java
@@ -0,0 +1,75 @@
+package com.baeldung.spring.kafka.multiplelisteners;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.kafka.config.KafkaListenerEndpointRegistry;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.kafka.listener.AcknowledgingConsumerAwareMessageListener;
+import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;
+import org.springframework.kafka.test.context.EmbeddedKafka;
+
+@SpringBootTest(classes = MultipleListenersApplicationKafkaApp.class)
+@EmbeddedKafka(partitions = 1, brokerProperties = { "listeners=PLAINTEXT://localhost:9092", "port=9092" })
+class KafkaMultipleListenersIntegrationTest {
+
+ @Autowired
+ private KafkaListenerEndpointRegistry registry;
+ @Autowired
+ private KafkaTemplate bookEventKafkaTemplate;
+
+ private static final String TOPIC = "books";
+
+ @Test
+ void givenEmbeddedKafkaBroker_whenSendingAMessage_thenMessageIsConsumedByAll3Listeners() throws Exception {
+ BookEvent bookEvent = new BookEvent("test-book-title-1", "test-book-desc-1", 2.0);
+ CountDownLatch latch = new CountDownLatch(3);
+
+ List extends ConcurrentMessageListenerContainer, ?>> bookListeners = registry.getAllListenerContainers()
+ .stream()
+ .map(c -> (ConcurrentMessageListenerContainer, ?>) c)
+ .collect(Collectors.toList());
+
+ bookListeners.forEach(listener -> {
+ listener.stop();
+ listener.getContainerProperties()
+ .setMessageListener((AcknowledgingConsumerAwareMessageListener) (data, acknowledgment, consumer) -> {
+ assertThat(data.value()).isEqualTo(bookEvent);
+ latch.countDown();
+ });
+ listener.start();
+ });
+
+ bookEventKafkaTemplate.send(TOPIC, UUID.randomUUID()
+ .toString(), bookEvent);
+
+ assertThat(bookListeners.size()).isEqualTo(3);
+ assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue();
+ }
+
+ @Test
+ void givenEmbeddedKafkaBroker_whenSendingThreeMessage_thenListenerPrintLogs() throws Exception {
+ CountDownLatch latch = new CountDownLatch(3);
+ Arrays.stream(new int[] { 1, 2, 3 })
+ .mapToObj(i -> new BookEvent(String.format("book %s", i), String.format("description %s", i), (double) i))
+ .forEach(bookEvent -> {
+ bookEventKafkaTemplate.send(TOPIC, UUID.randomUUID()
+ .toString(), bookEvent);
+ latch.countDown();
+ });
+
+ // wait for messages to be printed
+ Thread.sleep(1000);
+
+ assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue();
+ }
+}
diff --git a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/KafkaRetryableIntegrationTest.java b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/retryable/KafkaRetryableIntegrationTest.java
similarity index 95%
rename from spring-kafka-2/src/test/java/com/baeldung/spring/kafka/KafkaRetryableIntegrationTest.java
rename to spring-kafka-2/src/test/java/com/baeldung/spring/kafka/retryable/KafkaRetryableIntegrationTest.java
index 5417fee1ac..52cda85f90 100644
--- a/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/KafkaRetryableIntegrationTest.java
+++ b/spring-kafka-2/src/test/java/com/baeldung/spring/kafka/retryable/KafkaRetryableIntegrationTest.java
@@ -1,4 +1,4 @@
-package com.baeldung.spring.kafka;
+package com.baeldung.spring.kafka.retryable;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
@@ -17,6 +17,8 @@ import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;
import org.springframework.kafka.test.EmbeddedKafkaBroker;
import org.springframework.kafka.test.context.EmbeddedKafka;
+import com.baeldung.spring.kafka.retryable.Greeting;
+import com.baeldung.spring.kafka.retryable.RetryableApplicationKafkaApp;
import com.fasterxml.jackson.databind.ObjectMapper;
@SpringBootTest(classes = RetryableApplicationKafkaApp.class)
diff --git a/spring-reactive-modules/spring-5-data-reactive/pom.xml b/spring-reactive-modules/spring-5-data-reactive/pom.xml
index bf5170c621..0ed997b3f4 100644
--- a/spring-reactive-modules/spring-5-data-reactive/pom.xml
+++ b/spring-reactive-modules/spring-5-data-reactive/pom.xml
@@ -42,6 +42,7 @@
org.projectlombok
lombok
+ 1.18.22
io.projectreactor
diff --git a/spring-vault/src/main/java/com/baeldung/springvault/CredentialsService.java b/spring-vault/src/main/java/com/baeldung/springvault/CredentialsService.java
index 75bdd382cb..d9718252cb 100644
--- a/spring-vault/src/main/java/com/baeldung/springvault/CredentialsService.java
+++ b/spring-vault/src/main/java/com/baeldung/springvault/CredentialsService.java
@@ -5,54 +5,54 @@ import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import org.springframework.vault.core.VaultKeyValueOperations;
+import org.springframework.vault.core.VaultKeyValueOperationsSupport;
import org.springframework.vault.core.VaultTemplate;
import org.springframework.vault.support.VaultResponseSupport;
/**
* Sample service to demonstrate storing and retrieval of secrets.
- *
+ *
* NOTE: We need to configure Vault and provide the Vault uri in the properties file.
*
*/
@Service
public class CredentialsService {
+ private final VaultTemplate vaultTemplate;
+ private final VaultKeyValueOperations vaultKeyValueOperations;
+ private final CredentialsRepository credentialsRepository;
@Autowired
- private VaultTemplate vaultTemplate;
-
- @Autowired
- private CredentialsRepository credentialsRepository;
+ public CredentialsService(VaultTemplate vaultTemplate, CredentialsRepository credentialsRepository) {
+ this.vaultTemplate = vaultTemplate;
+ this.credentialsRepository = credentialsRepository;
+ this.vaultKeyValueOperations = vaultTemplate.opsForKeyValue("credentials/myapp", VaultKeyValueOperationsSupport.KeyValueBackend.KV_2);
+ }
/**
- * To Secure Credentials
- * @param credentials
- * @return VaultResponse
- * @throws URISyntaxException
- */
- public void secureCredentials(Credentials credentials) throws URISyntaxException {
-
- vaultTemplate.write("credentials/myapp", credentials);
+ * To Secure Credentials
+ * @param credentials
+ * @return VaultResponse
+ * @throws URISyntaxException
+ */
+ public void secureCredentials(Credentials credentials) {
+ vaultKeyValueOperations.put(credentials.getUsername(), credentials);
}
/**
* To Retrieve Credentials
* @return Credentials
- * @throws URISyntaxException
*/
- public Credentials accessCredentials() throws URISyntaxException {
-
- VaultResponseSupport response = vaultTemplate.read("credentials/myapp", Credentials.class);
+ public Credentials accessCredentials(String username) {
+ VaultResponseSupport response = vaultKeyValueOperations.get(username, Credentials.class);
return response.getData();
}
public Credentials saveCredentials(Credentials credentials) {
-
return credentialsRepository.save(credentials);
}
public Optional findById(String username) {
-
return credentialsRepository.findById(username);
}
-
}
diff --git a/spring-vault/src/test/java/com/baeldung/springvault/SpringContextLiveTest.java b/spring-vault/src/test/java/com/baeldung/springvault/SpringContextLiveTest.java
index 8139522745..6e2a61ca40 100644
--- a/spring-vault/src/test/java/com/baeldung/springvault/SpringContextLiveTest.java
+++ b/spring-vault/src/test/java/com/baeldung/springvault/SpringContextLiveTest.java
@@ -5,6 +5,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.vault.repository.configuration.EnableVaultRepositories;
/**
* This live test requires:
@@ -17,6 +18,7 @@ import org.springframework.test.context.junit4.SpringRunner;
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringVaultApplication.class)
+@EnableVaultRepositories
public class SpringContextLiveTest {
@Test
diff --git a/spring-vault/src/test/java/com/baeldung/springvault/VaultInitializer.java b/spring-vault/src/test/java/com/baeldung/springvault/VaultInitializer.java
index a823a4cd27..cf6b425581 100644
--- a/spring-vault/src/test/java/com/baeldung/springvault/VaultInitializer.java
+++ b/spring-vault/src/test/java/com/baeldung/springvault/VaultInitializer.java
@@ -7,11 +7,12 @@ import java.io.InputStreamReader;
import java.util.Map;
/**
- *
+ *
* This is a test class to initialize Vault.
*/
public class VaultInitializer implements Closeable {
+ public static final String API_VERSION = "v1";
private static final String UNSEAL_KEY = "Unseal Key:";
private static final String ROOT_TOKEN = "Root Token:";
@@ -27,7 +28,7 @@ public class VaultInitializer implements Closeable {
return unSealKey;
}
- public static final VaultInitializer initializeValut() {
+ public static final VaultInitializer initializeVault() {
VaultInitializer vaultProcess = new VaultInitializer();
vaultProcess.start();
// Secrets is by default enabled.
@@ -37,8 +38,9 @@ public class VaultInitializer implements Closeable {
@SuppressWarnings("unused")
private void enableSecrets() {
- System.out.println("Enabling Secrets at path credentials/myapp...");
- ProcessBuilder pb = new ProcessBuilder("vault", "secrets", "enable", "-path=credentials/myapp", "kv");
+ System.out.println("Enabling Secrets at path secret/...");
+ ProcessBuilder pb = new ProcessBuilder("vault", "secrets", "enable", "-path=credentials/myapp/", String.format("kv-%s", API_VERSION)); ;
+
Map map = pb.environment();
map.put("VAULT_ADDR", "http://127.0.0.1:8200");
try {
@@ -106,8 +108,7 @@ public class VaultInitializer implements Closeable {
@Override
public void close() throws IOException {
-
- System.out.println("stoping vault");
+ System.out.println("stopping vault");
vaultProcess.destroy();
}
}
diff --git a/spring-vault/src/test/java/com/baeldung/springvault/VaultIntegrationManualTest.java b/spring-vault/src/test/java/com/baeldung/springvault/VaultIntegrationManualTest.java
new file mode 100644
index 0000000000..9913a7dc5c
--- /dev/null
+++ b/spring-vault/src/test/java/com/baeldung/springvault/VaultIntegrationManualTest.java
@@ -0,0 +1,103 @@
+package com.baeldung.springvault;
+
+import static com.baeldung.springvault.VaultInitializer.API_VERSION;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.net.URISyntaxException;
+import java.util.Optional;
+
+import org.junit.Before;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.annotation.DirtiesContext.ClassMode;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.AnnotationConfigContextLoader;
+import org.springframework.vault.core.VaultTemplate;
+import org.springframework.vault.repository.configuration.EnableVaultRepositories;
+
+/**
+ * These tests are requiring the {@code vault} command to be installed and available in the executing
+ * platform. So, if you intend to run them in your environment, the please install the vault and then
+ * run the ignored tests.
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest(classes = CredentialsService.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ContextConfiguration(classes = VaultTestConfiguration.class, loader = AnnotationConfigContextLoader.class)
+@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
+@EnableVaultRepositories
+public class VaultIntegrationManualTest {
+ @Autowired
+ private CredentialsRepository credentialsRepository;
+
+ @Autowired
+ private VaultTemplate vaultTemplate;
+
+ private CredentialsService credentialsService;
+
+ @Before
+ public void setup() {
+ this.credentialsService = new CredentialsService(vaultTemplate, credentialsRepository);
+ }
+
+ /**
+ * Test to secure credentials.
+ *
+ * @throws URISyntaxException
+ */
+ @Test
+ public void givenCredentials_whenSecureCredentials_thenCredentialsSecuredSuccessfully() throws URISyntaxException {
+ // Given
+ Credentials credentials = new Credentials("username", "password");
+ // When
+ credentialsService.secureCredentials(credentials);
+ // Then
+ Credentials storedCredentials = credentialsService.accessCredentials(credentials.getUsername());
+ Assertions.assertNotNull(storedCredentials);
+ Assertions.assertEquals(credentials.getUsername(), storedCredentials.getUsername());
+ Assertions.assertEquals(credentials.getPassword(), storedCredentials.getPassword());
+ }
+
+ @Test
+ public void givenCredentials_whenSave_thenReturnCredentials() throws InterruptedException {
+ Assume.assumeTrue("v1".equals(API_VERSION));
+
+ credentialsService = new CredentialsService(vaultTemplate, credentialsRepository);
+ // Given
+ Credentials credentials = new Credentials("login", "password");
+
+ // When
+ Credentials savedCredentials = credentialsService.saveCredentials(credentials);
+
+ // Then
+ assertNotNull(savedCredentials);
+ assertEquals(credentials.getUsername(), savedCredentials.getUsername());
+ assertEquals(credentials.getPassword(), savedCredentials.getPassword());
+ }
+
+ @Test
+ public void givenId_whenFindById_thenReturnCredentials() {
+ // Given
+ Assume.assumeTrue("v1".equals(API_VERSION));
+ Credentials expectedCredentials = new Credentials("login", "p@ssw@rd");
+ credentialsService.saveCredentials(expectedCredentials);
+
+ // When
+ Optional retrievedCredentials = credentialsService.findById(expectedCredentials.getUsername());
+
+ // Then
+ assertNotNull(retrievedCredentials);
+ assertNotNull(retrievedCredentials.get());
+ assertEquals(expectedCredentials.getUsername(), retrievedCredentials.get()
+ .getUsername());
+ assertEquals(expectedCredentials.getPassword(), retrievedCredentials.get()
+ .getPassword());
+ }
+
+}
diff --git a/spring-vault/src/test/java/com/baeldung/springvault/VaultIntegrationTest.java b/spring-vault/src/test/java/com/baeldung/springvault/VaultIntegrationTest.java
deleted file mode 100644
index 7987ae9904..0000000000
--- a/spring-vault/src/test/java/com/baeldung/springvault/VaultIntegrationTest.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package com.baeldung.springvault;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
-import java.net.URISyntaxException;
-import java.util.Optional;
-
-import org.junit.FixMethodOrder;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.mockito.Mockito;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.annotation.DirtiesContext.ClassMode;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.junit4.SpringRunner;
-import org.springframework.test.context.support.AnnotationConfigContextLoader;
-
-/**
- * These tests are requiring the {@code vault} command to be installed and available in the executing
- * platform. So, if you intend to run them in your environment, the please install the vault and then
- * run the ignored tests.
- */
-@RunWith(SpringRunner.class)
-@SpringBootTest(classes = CredentialsService.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-@ContextConfiguration(classes = VaultTestConfiguration.class, loader = AnnotationConfigContextLoader.class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
-public class VaultIntegrationTest {
-
- @Autowired
- private CredentialsService credentialsService;
-
- @MockBean
- private CredentialsRepository credentialsRepository;
-
- /**
- * Test to secure credentials.
- *
- * @throws URISyntaxException
- */
- @Test
- @Ignore
- public void givenCredentials_whenSecureCredentials_thenCredentialsSecured() throws URISyntaxException {
- try {
- // Given
- Credentials credentials = new Credentials("username", "password");
-
- // When
- credentialsService.secureCredentials(credentials);
-
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- }
-
- /**
- * Test to access credentials
- *
- * @throws URISyntaxException
- */
- @Test
- @Ignore
- public void whenAccessCredentials_thenCredentialsRetrieved() throws URISyntaxException {
-
- // Given
- Credentials credentials = credentialsService.accessCredentials();
-
- // Then
- assertNotNull(credentials);
- assertEquals("username", credentials.getUsername());
- assertEquals("password", credentials.getPassword());
- }
-
- @Test
- @Ignore
- public void givenCredentials_whenSave_thenReturnCredentials() {
- // Given
- Credentials credentials = new Credentials("login", "password");
- Mockito.when(credentialsRepository.save(credentials))
- .thenReturn(credentials);
-
- // When
- Credentials savedCredentials = credentialsService.saveCredentials(credentials);
-
- // Then
- assertNotNull(savedCredentials);
- assertEquals(savedCredentials.getUsername(), credentials.getUsername());
- assertEquals(savedCredentials.getPassword(), credentials.getPassword());
- }
-
- @Test
- @Ignore
- public void givenId_whenFindById_thenReturnCredentials() {
- // Given
- Credentials credentials = new Credentials("login", "p@ssw@rd");
- Mockito.when(credentialsRepository.findById("login"))
- .thenReturn(Optional.of(credentials));
-
- // When
- Optional returnedCredentials = credentialsService.findById("login");
-
- // Then
- assertNotNull(returnedCredentials);
- assertNotNull(returnedCredentials.get());
- assertEquals(returnedCredentials.get()
- .getUsername(), credentials.getUsername());
- assertEquals(returnedCredentials.get()
- .getPassword(), credentials.getPassword());
- }
-
-}
diff --git a/spring-vault/src/test/java/com/baeldung/springvault/VaultTestConfiguration.java b/spring-vault/src/test/java/com/baeldung/springvault/VaultTestConfiguration.java
index 42f0bfbce9..2e3651d646 100644
--- a/spring-vault/src/test/java/com/baeldung/springvault/VaultTestConfiguration.java
+++ b/spring-vault/src/test/java/com/baeldung/springvault/VaultTestConfiguration.java
@@ -5,6 +5,7 @@ import java.net.URISyntaxException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.vault.annotation.VaultPropertySource;
import org.springframework.vault.authentication.TokenAuthentication;
import org.springframework.vault.client.VaultEndpoint;
import org.springframework.vault.core.VaultTemplate;
@@ -14,7 +15,7 @@ public class VaultTestConfiguration {
@Bean
public VaultInitializer vaultInitializer() {
- VaultInitializer vaultInitializer = VaultInitializer.initializeValut();
+ VaultInitializer vaultInitializer = VaultInitializer.initializeVault();
return vaultInitializer;
}
@@ -24,6 +25,5 @@ public class VaultTestConfiguration {
VaultInitializer vaultInitializer = vaultInitializer();
VaultTemplate vaultTemplate = new VaultTemplate(VaultEndpoint.from(new URI("http://localhost:8200")), new TokenAuthentication(vaultInitializer.getRootToken()));
return vaultTemplate;
-
}
}
diff --git a/testing-modules/gatling-java/Jenkinsfile b/testing-modules/gatling-java/Jenkinsfile
new file mode 100644
index 0000000000..0786788406
--- /dev/null
+++ b/testing-modules/gatling-java/Jenkinsfile
@@ -0,0 +1,20 @@
+pipeline {
+ agent any
+ stages {
+ stage("Build Maven") {
+ steps {
+ sh 'mvn -B clean package'
+ }
+ }
+ stage("Run Gatling") {
+ steps {
+ sh 'mvn gatling:test'
+ }
+ post {
+ always {
+ gatlingArchive()
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/testing-modules/gatling-java/README.md b/testing-modules/gatling-java/README.md
new file mode 100644
index 0000000000..71848ecfdc
--- /dev/null
+++ b/testing-modules/gatling-java/README.md
@@ -0,0 +1,7 @@
+### Relevant Articles:
+Load testing Rest End point using Gatling
+
+
+
+### Running a simualtion
+ To run the simulation from command prompt use mvn gatling:test
\ No newline at end of file
diff --git a/testing-modules/gatling-java/pom.xml b/testing-modules/gatling-java/pom.xml
new file mode 100644
index 0000000000..c759928cc5
--- /dev/null
+++ b/testing-modules/gatling-java/pom.xml
@@ -0,0 +1,79 @@
+
+
+ 4.0.0
+ org.baeldung
+ gatling-java
+ 1.0-SNAPSHOT
+ gatling-java
+
+
+ com.baeldung
+ testing-modules
+ 1.0.0-SNAPSHOT
+
+
+
+ io.gatling
+ gatling-app
+ ${gatling.version}
+
+
+ io.gatling.highcharts
+ gatling-charts-highcharts
+ ${gatling.version}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${spring.version}
+
+
+ org.projectlombok
+ lombok
+ 1.18.24
+ provided
+
+
+ com.github.javafaker
+ javafaker
+ ${faker.version}
+
+
+
+
+
+
+
+
+ net.alchim31.maven
+ scala-maven-plugin
+ ${scala-maven-plugin.version}
+
+
+
+
+
+ io.gatling
+ gatling-maven-plugin
+ ${gatling-maven-plugin.version}
+
+ org.baeldung.EmployeeRegistrationSimulation
+
+
+
+
+
+
+ 1.8
+ 1.8
+ UTF-8
+ 3.9.0
+ 4.2.9
+ 1.0.2
+ 2.7.5
+
+
+
\ No newline at end of file
diff --git a/testing-modules/gatling-java/src/main/java/org/baeldung/Address.java b/testing-modules/gatling-java/src/main/java/org/baeldung/Address.java
new file mode 100644
index 0000000000..2a8e6c60dc
--- /dev/null
+++ b/testing-modules/gatling-java/src/main/java/org/baeldung/Address.java
@@ -0,0 +1,13 @@
+package org.baeldung;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Builder
+@Data
+public class Address {
+ private String postCode;
+ private String Street;
+ private String houseNo;
+ private String city;
+}
diff --git a/testing-modules/gatling-java/src/main/java/org/baeldung/Application.java b/testing-modules/gatling-java/src/main/java/org/baeldung/Application.java
new file mode 100644
index 0000000000..fce18fe70c
--- /dev/null
+++ b/testing-modules/gatling-java/src/main/java/org/baeldung/Application.java
@@ -0,0 +1,12 @@
+package org.baeldung;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
\ No newline at end of file
diff --git a/testing-modules/gatling-java/src/main/java/org/baeldung/Employee.java b/testing-modules/gatling-java/src/main/java/org/baeldung/Employee.java
new file mode 100644
index 0000000000..c52130b175
--- /dev/null
+++ b/testing-modules/gatling-java/src/main/java/org/baeldung/Employee.java
@@ -0,0 +1,16 @@
+package org.baeldung;
+
+import java.util.Set;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+public class Employee {
+ private String empName;
+ private Address address;
+ private String id;
+ private Set projects;
+
+}
diff --git a/testing-modules/gatling-java/src/main/java/org/baeldung/EmployeeController.java b/testing-modules/gatling-java/src/main/java/org/baeldung/EmployeeController.java
new file mode 100644
index 0000000000..ce5d558d8e
--- /dev/null
+++ b/testing-modules/gatling-java/src/main/java/org/baeldung/EmployeeController.java
@@ -0,0 +1,99 @@
+package org.baeldung;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@RestController
+@RequestMapping("/api/employees")
+public class EmployeeController {
+
+ @GetMapping(produces = { MediaType.APPLICATION_JSON_VALUE })
+ public List getAllEmployees() {
+ return createEmployees();
+ }
+
+ @GetMapping("/{id}")
+ public Employee getEmployeeWithId(@PathVariable("id") Long id) {
+ log.info("Getting employee with ID '{}'", id);
+
+ List allEmployees = createEmployees();
+ return allEmployees.get(ThreadLocalRandom.current()
+ .nextInt(0, allEmployees.size()));
+ }
+
+ @PostMapping(consumes = { MediaType.APPLICATION_JSON_VALUE })
+ public ResponseEntity addEmployee(@RequestBody EmployeeCreationRequest request, UriComponentsBuilder uriComponentsBuilder) {
+
+ log.info("Creating new employee with employeeName: {}", request.getEmpName());
+
+ URI location = uriComponentsBuilder.path("/api/employees/{id}")
+ .buildAndExpand("99")
+ .toUri();
+ return ResponseEntity.created(location)
+ .build();
+ }
+
+ private List createEmployees() {
+
+ Set projects = new HashSet();
+ projects.add("proj1");
+ projects.add("proj2");
+
+ Employee employee1 = Employee.builder()
+ .id(UUID.randomUUID()
+ .toString())
+ .address(Address.builder()
+ .houseNo("1")
+ .city("London")
+ .postCode("HP17")
+ .build())
+ .projects(projects)
+ .empName("Andy")
+ .build();
+
+ Employee employee2 = Employee.builder()
+ .id(UUID.randomUUID()
+ .toString())
+ .address(Address.builder()
+ .houseNo("2")
+ .city("Cardiff")
+ .postCode("CF12")
+ .build())
+ .projects(projects)
+ .empName("Bob")
+ .build();
+
+ Employee employee3 = Employee.builder()
+ .id(UUID.randomUUID()
+ .toString())
+ .address(Address.builder()
+ .houseNo("4")
+ .city("Burmingham")
+ .postCode("BA4")
+ .build())
+ .projects(projects)
+ .empName("Clive")
+ .build();
+
+ return Arrays.asList(employee1, employee2, employee3);
+
+ }
+}
\ No newline at end of file
diff --git a/testing-modules/gatling-java/src/main/java/org/baeldung/EmployeeCreationRequest.java b/testing-modules/gatling-java/src/main/java/org/baeldung/EmployeeCreationRequest.java
new file mode 100644
index 0000000000..72c5e1ec27
--- /dev/null
+++ b/testing-modules/gatling-java/src/main/java/org/baeldung/EmployeeCreationRequest.java
@@ -0,0 +1,29 @@
+package org.baeldung;
+
+public class EmployeeCreationRequest {
+
+ private String empName;
+
+ private String empNumber;
+
+ public String getEmpName() {
+ return empName;
+ }
+
+ public void setEmpName(String empName) {
+ this.empName = empName;
+ }
+
+ @Override
+ public String toString() {
+ return "org.baeldung.EmployeeCreationRequest{" + "employeename='" + empName + '\'' + '}';
+ }
+
+ public String getEmpNumber() {
+ return empNumber;
+ }
+
+ public void setEmpNumber(String empNumber) {
+ this.empNumber = empNumber;
+ }
+}
\ No newline at end of file
diff --git a/testing-modules/gatling-java/src/test/java/org/baeldung/EmployeeRegistrationSimulation.java b/testing-modules/gatling-java/src/test/java/org/baeldung/EmployeeRegistrationSimulation.java
new file mode 100644
index 0000000000..de59273bbd
--- /dev/null
+++ b/testing-modules/gatling-java/src/test/java/org/baeldung/EmployeeRegistrationSimulation.java
@@ -0,0 +1,87 @@
+package org.baeldung;
+
+import static io.gatling.javaapi.core.CoreDsl.StringBody;
+import static io.gatling.javaapi.core.CoreDsl.global;
+import static io.gatling.javaapi.core.CoreDsl.rampUsersPerSec;
+import static io.gatling.javaapi.http.HttpDsl.header;
+import static io.gatling.javaapi.http.HttpDsl.http;
+import static io.gatling.javaapi.http.HttpDsl.status;
+
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import com.github.javafaker.Faker;
+
+import io.gatling.javaapi.core.CoreDsl;
+import io.gatling.javaapi.core.OpenInjectionStep.RampRate.RampRateOpenInjectionStep;
+import io.gatling.javaapi.core.ScenarioBuilder;
+import io.gatling.javaapi.core.Simulation;
+import io.gatling.javaapi.http.HttpDsl;
+import io.gatling.javaapi.http.HttpProtocolBuilder;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class EmployeeRegistrationSimulation extends Simulation {
+
+ private static final HttpProtocolBuilder HTTP_PROTOCOL_BUILDER = setupProtocolForSimulation();
+
+ private static final Iterator