recipients) {
+ this.recipients = recipients;
+ }
+
+ public void setCreatedAt(String createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public String getName() {
+ return content;
+ }
+
+ public void setName(String content) {
+ this.content = content;
+ }
+
+ public Optional<@Past String> getCreatedAt() {
+ return Optional.ofNullable(createdAt);
+ }
+
+}
diff --git a/jaxb/src/main/java/com/baeldung/jaxb/gen/ObjectFactory.java b/jaxb/src/main/java/com/baeldung/jaxb/gen/ObjectFactory.java
index 26cd5814ac..0a3da677ce 100644
--- a/jaxb/src/main/java/com/baeldung/jaxb/gen/ObjectFactory.java
+++ b/jaxb/src/main/java/com/baeldung/jaxb/gen/ObjectFactory.java
@@ -1,48 +1,48 @@
-
-package com.baeldung.jaxb.gen;
-
-import javax.xml.bind.annotation.XmlRegistry;
-
-
-/**
- * This object contains factory methods for each
- * Java content interface and Java element interface
- * generated in the com.baeldung.jaxb.gen package.
- * An ObjectFactory allows you to programatically
- * construct new instances of the Java representation
- * for XML content. The Java representation of XML
- * content can consist of schema derived interfaces
- * and classes representing the binding of schema
- * type definitions, element declarations and model
- * groups. Factory methods for each of these are
- * provided in this class.
- *
- */
-@XmlRegistry
-public class ObjectFactory {
-
-
- /**
- * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.baeldung.jaxb.gen
- *
- */
- public ObjectFactory() {
- }
-
- /**
- * Create an instance of {@link UserRequest }
- *
- */
- public UserRequest createUserRequest() {
- return new UserRequest();
- }
-
- /**
- * Create an instance of {@link UserResponse }
- *
- */
- public UserResponse createUserResponse() {
- return new UserResponse();
- }
-
-}
+
+package com.baeldung.jaxb.gen;
+
+import javax.xml.bind.annotation.XmlRegistry;
+
+
+/**
+ * This object contains factory methods for each
+ * Java content interface and Java element interface
+ * generated in the com.baeldung.jaxb.gen package.
+ *
An ObjectFactory allows you to programatically
+ * construct new instances of the Java representation
+ * for XML content. The Java representation of XML
+ * content can consist of schema derived interfaces
+ * and classes representing the binding of schema
+ * type definitions, element declarations and model
+ * groups. Factory methods for each of these are
+ * provided in this class.
+ *
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.baeldung.jaxb.gen
+ *
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link UserRequest }
+ *
+ */
+ public UserRequest createUserRequest() {
+ return new UserRequest();
+ }
+
+ /**
+ * Create an instance of {@link UserResponse }
+ *
+ */
+ public UserResponse createUserResponse() {
+ return new UserResponse();
+ }
+
+}
diff --git a/jaxb/src/main/java/com/baeldung/jaxb/gen/UserRequest.java b/jaxb/src/main/java/com/baeldung/jaxb/gen/UserRequest.java
index 4cfbeb8d46..1c1abc61a6 100644
--- a/jaxb/src/main/java/com/baeldung/jaxb/gen/UserRequest.java
+++ b/jaxb/src/main/java/com/baeldung/jaxb/gen/UserRequest.java
@@ -1,87 +1,87 @@
-
-package com.baeldung.jaxb.gen;
-
-import java.io.Serializable;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-
-
-/**
- *
Java class for UserRequest complex type.
- *
- *
The following schema fragment specifies the expected content contained within this class.
- *
- *
- * <complexType name="UserRequest">
- * <complexContent>
- * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- * <sequence>
- * <element name="id" type="{http://www.w3.org/2001/XMLSchema}int"/>
- * <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
- * </sequence>
- * </restriction>
- * </complexContent>
- * </complexType>
- *
- *
- *
- */
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "UserRequest", propOrder = {
- "id",
- "name"
-})
-@XmlRootElement(name = "userRequest")
-public class UserRequest
- implements Serializable
-{
-
- private final static long serialVersionUID = -1L;
- protected int id;
- @XmlElement(required = true)
- protected String name;
-
- /**
- * Gets the value of the id property.
- *
- */
- public int getId() {
- return id;
- }
-
- /**
- * Sets the value of the id property.
- *
- */
- public void setId(int value) {
- this.id = value;
- }
-
- /**
- * Gets the value of the name property.
- *
- * @return
- * possible object is
- * {@link String }
- *
- */
- public String getName() {
- return name;
- }
-
- /**
- * Sets the value of the name property.
- *
- * @param value
- * allowed object is
- * {@link String }
- *
- */
- public void setName(String value) {
- this.name = value;
- }
-
-}
+
+package com.baeldung.jaxb.gen;
+
+import java.io.Serializable;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * Java class for UserRequest complex type.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ * <complexType name="UserRequest">
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="id" type="{http://www.w3.org/2001/XMLSchema}int"/>
+ * <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ *
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "UserRequest", propOrder = {
+ "id",
+ "name"
+})
+@XmlRootElement(name = "userRequest")
+public class UserRequest
+ implements Serializable
+{
+
+ private final static long serialVersionUID = -1L;
+ protected int id;
+ @XmlElement(required = true)
+ protected String name;
+
+ /**
+ * Gets the value of the id property.
+ *
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ *
+ */
+ public void setId(int value) {
+ this.id = value;
+ }
+
+ /**
+ * Gets the value of the name property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the value of the name property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setName(String value) {
+ this.name = value;
+ }
+
+}
diff --git a/jaxb/src/main/java/com/baeldung/jaxb/gen/UserResponse.java b/jaxb/src/main/java/com/baeldung/jaxb/gen/UserResponse.java
index d86778403a..b80405e4a9 100644
--- a/jaxb/src/main/java/com/baeldung/jaxb/gen/UserResponse.java
+++ b/jaxb/src/main/java/com/baeldung/jaxb/gen/UserResponse.java
@@ -1,149 +1,149 @@
-
-package com.baeldung.jaxb.gen;
-
-import java.io.Serializable;
-import java.util.Calendar;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
-import org.w3._2001.xmlschema.Adapter1;
-
-
-/**
- * Java class for UserResponse complex type.
- *
- *
The following schema fragment specifies the expected content contained within this class.
- *
- *
- * <complexType name="UserResponse">
- * <complexContent>
- * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- * <sequence>
- * <element name="id" type="{http://www.w3.org/2001/XMLSchema}int"/>
- * <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
- * <element name="gender" type="{http://www.w3.org/2001/XMLSchema}string"/>
- * <element name="created" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
- * </sequence>
- * </restriction>
- * </complexContent>
- * </complexType>
- *
- *
- *
- */
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlType(name = "UserResponse", propOrder = {
- "id",
- "name",
- "gender",
- "created"
-})
-@XmlRootElement(name = "userResponse")
-public class UserResponse
- implements Serializable
-{
-
- private final static long serialVersionUID = -1L;
- protected int id;
- @XmlElement(required = true)
- protected String name;
- @XmlElement(required = true)
- protected String gender;
- @XmlElement(required = true, type = String.class)
- @XmlJavaTypeAdapter(Adapter1 .class)
- @XmlSchemaType(name = "dateTime")
- protected Calendar created;
-
- /**
- * Gets the value of the id property.
- *
- */
- public int getId() {
- return id;
- }
-
- /**
- * Sets the value of the id property.
- *
- */
- public void setId(int value) {
- this.id = value;
- }
-
- /**
- * Gets the value of the name property.
- *
- * @return
- * possible object is
- * {@link String }
- *
- */
- public String getName() {
- return name;
- }
-
- /**
- * Sets the value of the name property.
- *
- * @param value
- * allowed object is
- * {@link String }
- *
- */
- public void setName(String value) {
- this.name = value;
- }
-
- /**
- * Gets the value of the gender property.
- *
- * @return
- * possible object is
- * {@link String }
- *
- */
- public String getGender() {
- return gender;
- }
-
- /**
- * Sets the value of the gender property.
- *
- * @param value
- * allowed object is
- * {@link String }
- *
- */
- public void setGender(String value) {
- this.gender = value;
- }
-
- /**
- * Gets the value of the created property.
- *
- * @return
- * possible object is
- * {@link String }
- *
- */
- public Calendar getCreated() {
- return created;
- }
-
- /**
- * Sets the value of the created property.
- *
- * @param value
- * allowed object is
- * {@link String }
- *
- */
- public void setCreated(Calendar value) {
- this.created = value;
- }
-
-}
+
+package com.baeldung.jaxb.gen;
+
+import java.io.Serializable;
+import java.util.Calendar;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import org.w3._2001.xmlschema.Adapter1;
+
+
+/**
+ * Java class for UserResponse complex type.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ * <complexType name="UserResponse">
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="id" type="{http://www.w3.org/2001/XMLSchema}int"/>
+ * <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * <element name="gender" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * <element name="created" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ *
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "UserResponse", propOrder = {
+ "id",
+ "name",
+ "gender",
+ "created"
+})
+@XmlRootElement(name = "userResponse")
+public class UserResponse
+ implements Serializable
+{
+
+ private final static long serialVersionUID = -1L;
+ protected int id;
+ @XmlElement(required = true)
+ protected String name;
+ @XmlElement(required = true)
+ protected String gender;
+ @XmlElement(required = true, type = String.class)
+ @XmlJavaTypeAdapter(Adapter1 .class)
+ @XmlSchemaType(name = "dateTime")
+ protected Calendar created;
+
+ /**
+ * Gets the value of the id property.
+ *
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ *
+ */
+ public void setId(int value) {
+ this.id = value;
+ }
+
+ /**
+ * Gets the value of the name property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the value of the name property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setName(String value) {
+ this.name = value;
+ }
+
+ /**
+ * Gets the value of the gender property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getGender() {
+ return gender;
+ }
+
+ /**
+ * Sets the value of the gender property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setGender(String value) {
+ this.gender = value;
+ }
+
+ /**
+ * Gets the value of the created property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public Calendar getCreated() {
+ return created;
+ }
+
+ /**
+ * Sets the value of the created property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setCreated(Calendar value) {
+ this.created = value;
+ }
+
+}
diff --git a/jaxb/src/main/java/com/baeldung/jaxb/gen/package-info.java b/jaxb/src/main/java/com/baeldung/jaxb/gen/package-info.java
index 6384eab27f..639d00179c 100644
--- a/jaxb/src/main/java/com/baeldung/jaxb/gen/package-info.java
+++ b/jaxb/src/main/java/com/baeldung/jaxb/gen/package-info.java
@@ -1,2 +1,2 @@
-@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.baeldung.com/jaxb/gen", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
-package com.baeldung.jaxb.gen;
+@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.baeldung.com/jaxb/gen", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
+package com.baeldung.jaxb.gen;
diff --git a/jaxb/src/main/java/org/w3/_2001/xmlschema/Adapter1.java b/jaxb/src/main/java/org/w3/_2001/xmlschema/Adapter1.java
index b4865b5510..54b3c360dc 100644
--- a/jaxb/src/main/java/org/w3/_2001/xmlschema/Adapter1.java
+++ b/jaxb/src/main/java/org/w3/_2001/xmlschema/Adapter1.java
@@ -1,23 +1,23 @@
-
-package org.w3._2001.xmlschema;
-
-import java.util.Calendar;
-import javax.xml.bind.annotation.adapters.XmlAdapter;
-
-public class Adapter1
- extends XmlAdapter
-{
-
-
- public Calendar unmarshal(String value) {
- return (javax.xml.bind.DatatypeConverter.parseDateTime(value));
- }
-
- public String marshal(Calendar value) {
- if (value == null) {
- return null;
- }
- return (javax.xml.bind.DatatypeConverter.printDateTime(value));
- }
-
-}
+
+package org.w3._2001.xmlschema;
+
+import java.util.Calendar;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+public class Adapter1
+ extends XmlAdapter
+{
+
+
+ public Calendar unmarshal(String value) {
+ return (javax.xml.bind.DatatypeConverter.parseDateTime(value));
+ }
+
+ public String marshal(Calendar value) {
+ if (value == null) {
+ return null;
+ }
+ return (javax.xml.bind.DatatypeConverter.printDateTime(value));
+ }
+
+}
diff --git a/logging-modules/log4j2/src/main/java/com/baeldung/logging/log4j2threadinfo/Log4j2ThreadInfo.java b/logging-modules/log4j2/src/main/java/com/baeldung/logging/log4j2threadinfo/Log4j2ThreadInfo.java
new file mode 100644
index 0000000000..2c9b8870e2
--- /dev/null
+++ b/logging-modules/log4j2/src/main/java/com/baeldung/logging/log4j2threadinfo/Log4j2ThreadInfo.java
@@ -0,0 +1,18 @@
+package com.baeldung.logging.log4j2threadinfo;
+
+import java.util.stream.IntStream;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class Log4j2ThreadInfo {
+ private static final Logger logger = LogManager.getLogger(Log4j2ThreadInfo.class);
+
+ public static void main(String[] args) {
+ IntStream.range(0, 5).forEach(i -> {
+ Runnable runnable = () -> logger.info("Logging info");
+ Thread thread = new Thread(runnable);
+ thread.start();
+ });
+ }
+}
diff --git a/logging-modules/log4j2/src/main/resources/log4j2.xml b/logging-modules/log4j2/src/main/resources/log4j2.xml
new file mode 100644
index 0000000000..6c0bc75a94
--- /dev/null
+++ b/logging-modules/log4j2/src/main/resources/log4j2.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} --- thread_id="%tid" thread_name="%tn" thread_priority="%tp" --- [%p] %m%n
+
+
+
+
+
+ ${LOG_PATTERN}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/parent-boot-2/pom.xml b/parent-boot-2/pom.xml
index 109bf3b64f..b7f33de237 100644
--- a/parent-boot-2/pom.xml
+++ b/parent-boot-2/pom.xml
@@ -88,7 +88,7 @@
3.3.0
1.0.22.RELEASE
- 2.6.1
+ 2.6.3
1.9.1
diff --git a/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/connectionstatus/ConnectionValidation.java b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/connectionstatus/ConnectionValidation.java
new file mode 100644
index 0000000000..b6818d25c2
--- /dev/null
+++ b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/connectionstatus/ConnectionValidation.java
@@ -0,0 +1,65 @@
+package com.baeldung.connectionstatus;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+public class ConnectionValidation
+{
+
+ public static Connection getConnection()
+ throws Exception
+ {
+ Class.forName("org.h2.Driver");
+ String url = "jdbc:h2:mem:testdb";
+ return DriverManager.getConnection(url, "user", "password");
+ }
+
+ public static void runIfOpened(Connection connection)
+ throws SQLException
+ {
+ if (connection != null && !connection.isClosed()) {
+ // run sql statements
+ }
+ else {
+ // handle closed connection
+ }
+ }
+
+ public static void runIfValid(Connection connection)
+ throws SQLException
+ {
+ // Try to validate connection with a 5 seconds timeout
+ if (connection.isValid(5)) {
+ // run sql statements
+ }
+ else {
+ // handle invalid connection
+ }
+ }
+
+ public static void runIfConnectionValid(Connection connection)
+ {
+ if (isConnectionValid(connection)) {
+ // run sql statements
+ }
+ else {
+ // handle invalid connection
+ }
+ }
+
+ public static boolean isConnectionValid(Connection connection)
+ {
+ try {
+ if (connection != null && !connection.isClosed()) {
+ // Running a simple validation query
+ connection.prepareStatement("SELECT 1");
+ return true;
+ }
+ }
+ catch (SQLException e) {
+ // log some useful data here
+ }
+ return false;
+ }
+}
diff --git a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/connectionstatus/ConnectionValidationUnitTest.java b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/connectionstatus/ConnectionValidationUnitTest.java
new file mode 100644
index 0000000000..26356931cc
--- /dev/null
+++ b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/connectionstatus/ConnectionValidationUnitTest.java
@@ -0,0 +1,38 @@
+package com.baeldung.connectionstatus;
+
+import org.junit.jupiter.api.Test;
+
+import java.sql.Connection;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class ConnectionValidationUnitTest
+{
+ @Test
+ void givenConnectionObject_whenCreated_thenIsNotClosed()
+ throws Exception
+ {
+ Connection connection = ConnectionValidation.getConnection();
+ assertNotNull(connection);
+ assertFalse(connection.isClosed());
+ }
+
+ @Test
+ void givenConnectionObject_whenCreated_thenIsValid()
+ throws Exception
+ {
+ Connection connection = ConnectionValidation.getConnection();
+ assertTrue(connection.isValid(0));
+ }
+
+ @Test
+ void givenConnectionObject_whenValidated_thenIsValid()
+ throws Exception
+ {
+ Connection connection = ConnectionValidation.getConnection();
+ assertTrue(ConnectionValidation.isConnectionValid(connection));
+ }
+
+}
diff --git a/persistence-modules/java-cassandra/README.md b/persistence-modules/java-cassandra/README.md
index 735aabdf62..792ef143ab 100644
--- a/persistence-modules/java-cassandra/README.md
+++ b/persistence-modules/java-cassandra/README.md
@@ -1,4 +1,6 @@
### Relevant Articles:
+
+- [Cassandra Batch in Cassandra Query Language and Java](https://www.baeldung.com/java-cql-cassandra-batch)
- [A Guide to Cassandra with Java](http://www.baeldung.com/cassandra-with-java)
- [Intro to DataStax Java Driver for Apache Cassandra](https://www.baeldung.com/cassandra-datastax-java-driver)
- [CQL Data Types](https://www.baeldung.com/cassandra-data-types)
diff --git a/persistence-modules/java-mongodb/README.md b/persistence-modules/java-mongodb/README.md
index 34acd60c57..fe30c2999e 100644
--- a/persistence-modules/java-mongodb/README.md
+++ b/persistence-modules/java-mongodb/README.md
@@ -12,3 +12,4 @@ This module contains articles about MongoDB in Java.
- [MongoDB Aggregations Using Java](https://www.baeldung.com/java-mongodb-aggregations)
- [BSON to JSON Document Conversion in Java](https://www.baeldung.com/java-convert-bson-to-json)
- [How to Check Field Existence in MongoDB?](https://www.baeldung.com/mongodb-check-field-exists)
+- [Get Last Inserted Document ID in MongoDB With Java Driver](https://www.baeldung.com/java-mongodb-last-inserted-id)
diff --git a/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/objectid/RetrieveIdExample.java b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/objectid/RetrieveIdExample.java
new file mode 100644
index 0000000000..74279bbfcd
--- /dev/null
+++ b/persistence-modules/java-mongodb/src/main/java/com/baeldung/mongo/objectid/RetrieveIdExample.java
@@ -0,0 +1,57 @@
+package com.baeldung.mongo.objectid;
+
+import java.util.Date;
+
+import org.bson.Document;
+import org.bson.types.ObjectId;
+
+import com.mongodb.MongoClient;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoDatabase;
+
+public class RetrieveIdExample {
+
+ public static void main(String[] args) {
+
+ try ( MongoClient mongoClient = new MongoClient("localhost", 27017) ) {
+
+ MongoDatabase database = mongoClient.getDatabase("myMongoDb");
+ MongoCollection collection = database.getCollection("example");
+
+// Create document with user-generated ID
+ ObjectId generatedId = new ObjectId();
+
+ System.out.println(generatedId.toString());
+
+ Document document = new Document();
+ document.put("_id", generatedId);
+ document.put("name", "Shubham");
+ document.put("company", "Baeldung");
+ collection.insertOne(document);
+
+// Check that the ID of the document is still the one we set
+ System.out.println(document.getObjectId("_id").equals(generatedId));
+
+
+// Create a second document by injecting the ID in the constructor
+
+ ObjectId generatedId2 = ObjectId.get();
+
+ Document document2 = new Document("_id", generatedId2);
+ document2.put("name", "Shubham");
+ document2.put("company", "Baeldung");
+ collection.insertOne(document2);
+
+ Date creationDate = generatedId.getDate();
+ System.out.println(creationDate);
+
+ int timestamp = generatedId.getTimestamp();
+
+ } catch (Exception e) {
+
+ System.out.println(e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/SpringContextTest.java b/persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/SpringContextTest.java
index 22bd5c6551..83b7b227b3 100644
--- a/persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/SpringContextTest.java
+++ b/persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/SpringContextTest.java
@@ -32,10 +32,10 @@ public class SpringContextTest {
public static final String KEYSPACE_ACTIVATE_QUERY = "USE testKeySpace;";
public static final String DATA_TABLE_NAME = "book";
-
+
@Autowired
private CassandraAdminOperations adminTemplate;
-
+
@BeforeClass
public static void startCassandraEmbedded() throws InterruptedException, TTransportException, ConfigurationException, IOException {
EmbeddedCassandraServerHelper.startEmbeddedCassandra();
@@ -47,14 +47,14 @@ public class SpringContextTest {
}
@Before
- public void createTable() throws InterruptedException, TTransportException, ConfigurationException, IOException {
- adminTemplate.createTable(true, CqlIdentifier.cqlId(DATA_TABLE_NAME), Book.class, new HashMap());
+ public void createTable() {
+ adminTemplate.createTable(true, CqlIdentifier.cqlId(DATA_TABLE_NAME), Book.class, new HashMap<>());
}
-
+
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
-
+
@After
public void dropTable() {
adminTemplate.dropTable(CqlIdentifier.cqlId(DATA_TABLE_NAME));
diff --git a/persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/BookRepositoryIntegrationTest.java b/persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/BookRepositoryLiveTest.java
similarity index 92%
rename from persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/BookRepositoryIntegrationTest.java
rename to persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/BookRepositoryLiveTest.java
index 55e968d6f2..d5758c3574 100644
--- a/persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/BookRepositoryIntegrationTest.java
+++ b/persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/BookRepositoryLiveTest.java
@@ -1,17 +1,15 @@
package com.baeldung.spring.data.cassandra.repository;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import java.io.IOException;
-import java.util.HashMap;
-
+import com.baeldung.spring.data.cassandra.config.CassandraConfig;
import com.baeldung.spring.data.cassandra.model.Book;
+import com.datastax.driver.core.Cluster;
+import com.datastax.driver.core.Session;
+import com.datastax.driver.core.utils.UUIDs;
+import com.google.common.collect.ImmutableSet;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.thrift.transport.TTransportException;
-import com.baeldung.spring.data.cassandra.config.CassandraConfig;
import org.cassandraunit.utils.EmbeddedCassandraServerHelper;
import org.junit.After;
import org.junit.AfterClass;
@@ -25,15 +23,24 @@ import org.springframework.data.cassandra.core.CassandraAdminOperations;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-import com.datastax.driver.core.Cluster;
-import com.datastax.driver.core.Session;
-import com.datastax.driver.core.utils.UUIDs;
-import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.util.HashMap;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+/**
+ * Live test for Cassandra testing.
+ *
+ * This can be converted to IntegrationTest once cassandra-unit tests can be executed in parallel and
+ * multiple test servers started as part of test suite.
+ *
+ * Open cassandra-unit issue for parallel execution: https://github.com/jsevellec/cassandra-unit/issues/155
+ */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CassandraConfig.class)
-public class BookRepositoryIntegrationTest {
- private static final Log LOGGER = LogFactory.getLog(BookRepositoryIntegrationTest.class);
+public class BookRepositoryLiveTest {
+ private static final Log LOGGER = LogFactory.getLog(BookRepositoryLiveTest.class);
public static final String KEYSPACE_CREATION_QUERY = "CREATE KEYSPACE IF NOT EXISTS testKeySpace WITH replication = { 'class': 'SimpleStrategy', 'replication_factor': '3' };";
@@ -47,8 +54,6 @@ public class BookRepositoryIntegrationTest {
@Autowired
private CassandraAdminOperations adminTemplate;
- //
-
@BeforeClass
public static void startCassandraEmbedded() throws InterruptedException, TTransportException, ConfigurationException, IOException {
EmbeddedCassandraServerHelper.startEmbeddedCassandra();
@@ -62,8 +67,8 @@ public class BookRepositoryIntegrationTest {
}
@Before
- public void createTable() throws InterruptedException, TTransportException, ConfigurationException, IOException {
- adminTemplate.createTable(true, CqlIdentifier.cqlId(DATA_TABLE_NAME), Book.class, new HashMap());
+ public void createTable() {
+ adminTemplate.createTable(true, CqlIdentifier.cqlId(DATA_TABLE_NAME), Book.class, new HashMap<>());
}
@Test
diff --git a/persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/CassandraTemplateIntegrationTest.java b/persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/CassandraTemplateLiveTest.java
similarity index 93%
rename from persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/CassandraTemplateIntegrationTest.java
rename to persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/CassandraTemplateLiveTest.java
index 90ae68ba98..bc05302d13 100644
--- a/persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/CassandraTemplateIntegrationTest.java
+++ b/persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/CassandraTemplateLiveTest.java
@@ -1,17 +1,13 @@
package com.baeldung.spring.data.cassandra.repository;
-import static junit.framework.TestCase.assertNull;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
import com.baeldung.spring.data.cassandra.config.CassandraConfig;
import com.baeldung.spring.data.cassandra.model.Book;
+import com.datastax.driver.core.Cluster;
+import com.datastax.driver.core.Session;
+import com.datastax.driver.core.querybuilder.QueryBuilder;
+import com.datastax.driver.core.querybuilder.Select;
+import com.datastax.driver.core.utils.UUIDs;
+import com.google.common.collect.ImmutableSet;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -30,17 +26,28 @@ import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-import com.datastax.driver.core.Cluster;
-import com.datastax.driver.core.Session;
-import com.datastax.driver.core.querybuilder.QueryBuilder;
-import com.datastax.driver.core.querybuilder.Select;
-import com.datastax.driver.core.utils.UUIDs;
-import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import static junit.framework.TestCase.assertNull;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Live test for Cassandra testing.
+ *
+ * This can be converted to IntegrationTest once cassandra-unit tests can be executed in parallel and
+ * multiple test servers started as part of test suite.
+ *
+ * Open cassandra-unit issue for parallel execution: https://github.com/jsevellec/cassandra-unit/issues/155
+ */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CassandraConfig.class)
-public class CassandraTemplateIntegrationTest {
- private static final Log LOGGER = LogFactory.getLog(CassandraTemplateIntegrationTest.class);
+public class CassandraTemplateLiveTest {
+ private static final Log LOGGER = LogFactory.getLog(CassandraTemplateLiveTest.class);
public static final String KEYSPACE_CREATION_QUERY = "CREATE KEYSPACE IF NOT EXISTS testKeySpace " + "WITH replication = { 'class': 'SimpleStrategy', 'replication_factor': '3' };";
@@ -54,8 +61,6 @@ public class CassandraTemplateIntegrationTest {
@Autowired
private CassandraOperations cassandraTemplate;
- //
-
@BeforeClass
public static void startCassandraEmbedded() throws InterruptedException, TTransportException, ConfigurationException, IOException {
EmbeddedCassandraServerHelper.startEmbeddedCassandra();
@@ -69,8 +74,8 @@ public class CassandraTemplateIntegrationTest {
}
@Before
- public void createTable() throws InterruptedException, TTransportException, ConfigurationException, IOException {
- adminTemplate.createTable(true, CqlIdentifier.cqlId(DATA_TABLE_NAME), Book.class, new HashMap());
+ public void createTable() {
+ adminTemplate.createTable(true, CqlIdentifier.cqlId(DATA_TABLE_NAME), Book.class, new HashMap<>());
}
@Test
@@ -111,7 +116,7 @@ public class CassandraTemplateIntegrationTest {
}
@Test
- public void whenDeletingASelectedBook_thenNotAvailableOnRetrieval() throws InterruptedException {
+ public void whenDeletingASelectedBook_thenNotAvailableOnRetrieval() {
final Book javaBook = new Book(UUIDs.timeBased(), "Head First Java", "OReilly Media", ImmutableSet.of("Computer", "Software"));
cassandraTemplate.insert(javaBook);
cassandraTemplate.delete(javaBook);
diff --git a/persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/CqlQueriesIntegrationTest.java b/persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/CqlQueriesLiveTest.java
similarity index 90%
rename from persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/CqlQueriesIntegrationTest.java
rename to persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/CqlQueriesLiveTest.java
index f948218807..e1c67a1724 100644
--- a/persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/CqlQueriesIntegrationTest.java
+++ b/persistence-modules/spring-data-cassandra/src/test/java/com/baeldung/spring/data/cassandra/repository/CqlQueriesLiveTest.java
@@ -1,19 +1,16 @@
package com.baeldung.spring.data.cassandra.repository;
-import static junit.framework.TestCase.assertEquals;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.UUID;
-
-import org.apache.cassandra.exceptions.ConfigurationException;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.thrift.transport.TTransportException;
import com.baeldung.spring.data.cassandra.config.CassandraConfig;
import com.baeldung.spring.data.cassandra.model.Book;
+import com.datastax.driver.core.Cluster;
+import com.datastax.driver.core.Session;
+import com.datastax.driver.core.querybuilder.Insert;
+import com.datastax.driver.core.querybuilder.QueryBuilder;
+import com.datastax.driver.core.querybuilder.Select;
+import com.datastax.driver.core.utils.UUIDs;
+import com.google.common.collect.ImmutableSet;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.cassandraunit.utils.EmbeddedCassandraServerHelper;
import org.junit.After;
import org.junit.AfterClass;
@@ -28,18 +25,25 @@ import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-import com.datastax.driver.core.Cluster;
-import com.datastax.driver.core.Session;
-import com.datastax.driver.core.querybuilder.Insert;
-import com.datastax.driver.core.querybuilder.QueryBuilder;
-import com.datastax.driver.core.querybuilder.Select;
-import com.datastax.driver.core.utils.UUIDs;
-import com.google.common.collect.ImmutableSet;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.UUID;
+import static junit.framework.TestCase.assertEquals;
+
+/**
+ * Live test for Cassandra testing.
+ *
+ * This can be converted to IntegrationTest once cassandra-unit tests can be executed in parallel and
+ * multiple test servers started as part of test suite.
+ *
+ * Open cassandra-unit issue for parallel execution: https://github.com/jsevellec/cassandra-unit/issues/155
+ */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CassandraConfig.class)
-public class CqlQueriesIntegrationTest {
- private static final Log LOGGER = LogFactory.getLog(CqlQueriesIntegrationTest.class);
+public class CqlQueriesLiveTest {
+ private static final Log LOGGER = LogFactory.getLog(CqlQueriesLiveTest.class);
public static final String KEYSPACE_CREATION_QUERY = "CREATE KEYSPACE IF NOT EXISTS testKeySpace " + "WITH replication = { 'class': 'SimpleStrategy', 'replication_factor': '3' };";
@@ -53,10 +57,8 @@ public class CqlQueriesIntegrationTest {
@Autowired
private CassandraOperations cassandraTemplate;
- //
-
@BeforeClass
- public static void startCassandraEmbedded() throws InterruptedException, TTransportException, ConfigurationException, IOException {
+ public static void startCassandraEmbedded() throws Exception {
EmbeddedCassandraServerHelper.startEmbeddedCassandra(25000);
final Cluster cluster = Cluster.builder().addContactPoints("127.0.0.1").withPort(9142).build();
LOGGER.info("Server Started at 127.0.0.1:9142... ");
@@ -68,8 +70,8 @@ public class CqlQueriesIntegrationTest {
}
@Before
- public void createTable() throws InterruptedException, TTransportException, ConfigurationException, IOException {
- adminTemplate.createTable(true, CqlIdentifier.cqlId(DATA_TABLE_NAME), Book.class, new HashMap());
+ public void createTable() {
+ adminTemplate.createTable(true, CqlIdentifier.cqlId(DATA_TABLE_NAME), Book.class, new HashMap<>());
}
@Test
diff --git a/persistence-modules/spring-data-jpa-enterprise-2/README.md b/persistence-modules/spring-data-jpa-enterprise-2/README.md
new file mode 100644
index 0000000000..9bb08cc497
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise-2/README.md
@@ -0,0 +1,18 @@
+## Spring Data JPA - Enterprise
+
+This module contains articles about Spring Data JPA used in enterprise applications such as transactions, sessions, naming conventions and more
+
+### Relevant Articles:
+
+- [Spring JPA – Multiple Databases](https://www.baeldung.com/spring-data-jpa-multiple-databases)
+- [Pagination and Sorting using Spring Data JPA](https://www.baeldung.com/spring-data-jpa-pagination-sorting)
+
+### Eclipse Config
+After importing the project into Eclipse, you may see the following error:
+"No persistence xml file found in project"
+
+This can be ignored:
+- Project -> Properties -> Java Persistance -> JPA -> Error/Warnings -> Select Ignore on "No persistence xml file found in project"
+Or:
+- Eclipse -> Preferences - Validation - disable the "Build" execution of the JPA Validator
+
diff --git a/persistence-modules/spring-data-jpa-enterprise-2/pom.xml b/persistence-modules/spring-data-jpa-enterprise-2/pom.xml
new file mode 100644
index 0000000000..f35ee378d1
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise-2/pom.xml
@@ -0,0 +1,36 @@
+
+
+ 4.0.0
+ spring-data-jpa-enterprise-2
+ spring-data-jpa-enterprise-2
+
+
+ com.baeldung
+ parent-boot-2
+ 0.0.1-SNAPSHOT
+ ../../parent-boot-2
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ com.h2database
+ h2
+
+
+ com.google.guava
+ guava
+ ${guava.version}
+
+
+
+
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/Application.java b/persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/Application.java
new file mode 100644
index 0000000000..37dbe7dab8
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/Application.java
@@ -0,0 +1,13 @@
+package com.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);
+ }
+
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/MultipleDbApplication.java b/persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/MultipleDbApplication.java
similarity index 100%
rename from persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/MultipleDbApplication.java
rename to persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/MultipleDbApplication.java
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceProductAutoConfiguration.java b/persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/PersistenceProductAutoConfiguration.java
similarity index 97%
rename from persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceProductAutoConfiguration.java
rename to persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/PersistenceProductAutoConfiguration.java
index a6f8f0829f..bc7ab57b06 100644
--- a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceProductAutoConfiguration.java
+++ b/persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/PersistenceProductAutoConfiguration.java
@@ -8,7 +8,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceProductConfiguration.java b/persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/PersistenceProductConfiguration.java
similarity index 100%
rename from persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceProductConfiguration.java
rename to persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/PersistenceProductConfiguration.java
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceUserAutoConfiguration.java b/persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/PersistenceUserAutoConfiguration.java
similarity index 97%
rename from persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceUserAutoConfiguration.java
rename to persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/PersistenceUserAutoConfiguration.java
index e04a1621b2..8080885b37 100644
--- a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceUserAutoConfiguration.java
+++ b/persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/PersistenceUserAutoConfiguration.java
@@ -8,7 +8,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceUserConfiguration.java b/persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/PersistenceUserConfiguration.java
similarity index 100%
rename from persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceUserConfiguration.java
rename to persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/PersistenceUserConfiguration.java
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/dao/product/ProductRepository.java b/persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/dao/product/ProductRepository.java
old mode 100755
new mode 100644
similarity index 100%
rename from persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/dao/product/ProductRepository.java
rename to persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/dao/product/ProductRepository.java
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/dao/user/PossessionRepository.java b/persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/dao/user/PossessionRepository.java
similarity index 100%
rename from persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/dao/user/PossessionRepository.java
rename to persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/dao/user/PossessionRepository.java
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/dao/user/UserRepository.java b/persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/dao/user/UserRepository.java
similarity index 100%
rename from persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/dao/user/UserRepository.java
rename to persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/dao/user/UserRepository.java
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/model/product/Product.java b/persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/model/product/Product.java
old mode 100755
new mode 100644
similarity index 100%
rename from persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/model/product/Product.java
rename to persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/model/product/Product.java
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/model/user/Possession.java b/persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/model/user/Possession.java
similarity index 100%
rename from persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/model/user/Possession.java
rename to persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/model/user/Possession.java
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/model/user/User.java b/persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/model/user/User.java
similarity index 100%
rename from persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/model/user/User.java
rename to persistence-modules/spring-data-jpa-enterprise-2/src/main/java/com/baeldung/multipledb/model/user/User.java
diff --git a/persistence-modules/spring-data-jpa-enterprise-2/src/main/resources/application.properties b/persistence-modules/spring-data-jpa-enterprise-2/src/main/resources/application.properties
new file mode 100644
index 0000000000..0ca1872207
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise-2/src/main/resources/application.properties
@@ -0,0 +1,15 @@
+
+spring.datasource.url=jdbc:h2:mem:baeldung
+
+# JPA-Schema-Generation
+# Use below configuration to generate database schema create commands based on the entity models
+# and export them into the create.sql file
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=create.sql
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-source=metadata
+#spring.jpa.properties.hibernate.format_sql=true
+
+spring.jpa.show-sql=false
+
+#hibernate.dialect=org.hibernate.dialect.H2Dialect
+spring.jpa.properties.hibernate.id.new_generator_mappings=false
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/resources/persistence-multiple-db-boot.properties b/persistence-modules/spring-data-jpa-enterprise-2/src/main/resources/persistence-multiple-db-boot.properties
similarity index 100%
rename from persistence-modules/spring-data-jpa-enterprise/src/main/resources/persistence-multiple-db-boot.properties
rename to persistence-modules/spring-data-jpa-enterprise-2/src/main/resources/persistence-multiple-db-boot.properties
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/resources/persistence-multiple-db.properties b/persistence-modules/spring-data-jpa-enterprise-2/src/main/resources/persistence-multiple-db.properties
similarity index 100%
rename from persistence-modules/spring-data-jpa-enterprise/src/main/resources/persistence-multiple-db.properties
rename to persistence-modules/spring-data-jpa-enterprise-2/src/main/resources/persistence-multiple-db.properties
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/multipledb/JpaMultipleDBIntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise-2/src/test/java/com/baeldung/multipledb/JpaMultipleDBIntegrationTest.java
similarity index 100%
rename from persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/multipledb/JpaMultipleDBIntegrationTest.java
rename to persistence-modules/spring-data-jpa-enterprise-2/src/test/java/com/baeldung/multipledb/JpaMultipleDBIntegrationTest.java
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/multipledb/ProductRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise-2/src/test/java/com/baeldung/multipledb/ProductRepositoryIntegrationTest.java
similarity index 97%
rename from persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/multipledb/ProductRepositoryIntegrationTest.java
rename to persistence-modules/spring-data-jpa-enterprise-2/src/test/java/com/baeldung/multipledb/ProductRepositoryIntegrationTest.java
index 9bfba61a3b..831790af95 100644
--- a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/multipledb/ProductRepositoryIntegrationTest.java
+++ b/persistence-modules/spring-data-jpa-enterprise-2/src/test/java/com/baeldung/multipledb/ProductRepositoryIntegrationTest.java
@@ -18,12 +18,10 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
-import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
-import com.baeldung.multipledb.PersistenceProductConfiguration;
import com.baeldung.multipledb.dao.product.ProductRepository;
import com.baeldung.multipledb.model.product.Product;
diff --git a/persistence-modules/spring-data-jpa-enterprise-2/src/test/resources/logback-test.xml b/persistence-modules/spring-data-jpa-enterprise-2/src/test/resources/logback-test.xml
new file mode 100644
index 0000000000..1595326253
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise-2/src/test/resources/logback-test.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ [%d{ISO8601}]-[%thread] %-5level %logger - %msg%n
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-enterprise/README.md b/persistence-modules/spring-data-jpa-enterprise/README.md
index 42fbecc880..ca89bd54e7 100644
--- a/persistence-modules/spring-data-jpa-enterprise/README.md
+++ b/persistence-modules/spring-data-jpa-enterprise/README.md
@@ -4,9 +4,7 @@ This module contains articles about Spring Data JPA used in enterprise applicati
### Relevant Articles:
-- [Spring JPA – Multiple Databases](https://www.baeldung.com/spring-data-jpa-multiple-databases)
- [Spring Data Java 8 Support](https://www.baeldung.com/spring-data-java-8)
-- [Pagination and Sorting using Spring Data JPA](https://www.baeldung.com/spring-data-jpa-pagination-sorting)
- [DB Integration Tests with Spring Boot and Testcontainers](https://www.baeldung.com/spring-boot-testcontainers-integration-test)
- [A Guide to Spring’s Open Session In View](https://www.baeldung.com/spring-open-session-in-view)
- [Working with Lazy Element Collections in JPA](https://www.baeldung.com/java-jpa-lazy-collections)
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/SpringJpaContextIntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/SpringJpaContextIntegrationTest.java
index f3697bf39f..ecaa83f3f3 100644
--- a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/SpringJpaContextIntegrationTest.java
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/SpringJpaContextIntegrationTest.java
@@ -8,14 +8,10 @@ import org.springframework.test.context.junit4.SpringRunner;
import com.baeldung.boot.Application;
import com.baeldung.boot.config.PersistenceConfiguration;
-import com.baeldung.multipledb.PersistenceProductConfiguration;
-import com.baeldung.multipledb.PersistenceUserConfiguration;
@RunWith(SpringRunner.class)
@DataJpaTest(excludeAutoConfiguration = {
- PersistenceConfiguration.class,
- PersistenceUserConfiguration.class,
- PersistenceProductConfiguration.class })
+ PersistenceConfiguration.class })
@ContextConfiguration(classes = Application.class)
public class SpringJpaContextIntegrationTest {
diff --git a/persistence-modules/spring-data-jpa-filtering/pom.xml b/persistence-modules/spring-data-jpa-filtering/pom.xml
index 287a3136fd..9c10f4a997 100644
--- a/persistence-modules/spring-data-jpa-filtering/pom.xml
+++ b/persistence-modules/spring-data-jpa-filtering/pom.xml
@@ -67,6 +67,7 @@
com.baeldung.boot.Application
1.10.6
42.2.5
+ 2.6.1
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-repo-2/README.md b/persistence-modules/spring-data-jpa-repo-2/README.md
index be5bab1b56..6403510e6f 100644
--- a/persistence-modules/spring-data-jpa-repo-2/README.md
+++ b/persistence-modules/spring-data-jpa-repo-2/README.md
@@ -1,7 +1,9 @@
## Spring Data JPA - Repositories
### Relevant Articles:
+
- [Introduction to Spring Data JPA](https://www.baeldung.com/the-persistence-layer-with-spring-data-jpa)
- [Performance Difference Between save() and saveAll() in Spring Data](https://www.baeldung.com/spring-data-save-saveall)
- [LIKE Queries in Spring JPA Repositories](https://www.baeldung.com/spring-jpa-like-queries)
+- [How to Access EntityManager with Spring Data](https://www.baeldung.com/spring-data-entitymanager)
- More articles: [[<-- prev]](../spring-data-jpa-repo)
diff --git a/persistence-modules/spring-data-mongodb-reactive/pom.xml b/persistence-modules/spring-data-mongodb-reactive/pom.xml
index 0e4efed6e6..ac2bf14635 100644
--- a/persistence-modules/spring-data-mongodb-reactive/pom.xml
+++ b/persistence-modules/spring-data-mongodb-reactive/pom.xml
@@ -124,7 +124,7 @@
- 5.3.13
+ 5.3.15
4.5.2
3.3.1.RELEASE
3.2.6
diff --git a/persistence-modules/spring-mybatis/pom.xml b/persistence-modules/spring-mybatis/pom.xml
index eb0ebd723d..65a8581f97 100644
--- a/persistence-modules/spring-mybatis/pom.xml
+++ b/persistence-modules/spring-mybatis/pom.xml
@@ -78,7 +78,7 @@
- 5.3.13
+ 5.3.15
2.0.6
3.5.2
diff --git a/pom.xml b/pom.xml
index 6219bbc692..f5378f9961 100644
--- a/pom.xml
+++ b/pom.xml
@@ -353,7 +353,7 @@
apache-cxf
apache-kafka
apache-libraries
- apache-olingo/olingo2
+ apache-olingo
apache-poi
apache-rocketmq
apache-shiro
@@ -422,6 +422,7 @@
graphql/graphql-java
+ graphql/graphql-dgs
grpc
gson
guava-modules
@@ -838,7 +839,7 @@
apache-cxf
apache-kafka
apache-libraries
- apache-olingo/olingo2
+ apache-olingo
apache-poi
apache-rocketmq
apache-shiro
@@ -1332,6 +1333,7 @@
core-java-modules/core-java-io-conversions-2
core-java-modules/core-java-jpms
core-java-modules/core-java-os
+ core-java-modules/core-java-string-algorithms-3
core-java-modules/core-java-string-operations-3
core-java-modules/core-java-string-operations-4
core-java-modules/core-java-time-measurements
diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml
index ac0deaa9e5..4925530a35 100644
--- a/spring-boot-modules/pom.xml
+++ b/spring-boot-modules/pom.xml
@@ -52,6 +52,7 @@
spring-boot-libraries
spring-boot-libraries-2
spring-boot-logging-log4j2
+ spring-boot-multiple-datasources
spring-boot-mvc
spring-boot-mvc-2
spring-boot-mvc-3
diff --git a/spring-boot-modules/spring-boot-2/pom.xml b/spring-boot-modules/spring-boot-2/pom.xml
index 65bacb7c47..08dc517fa0 100644
--- a/spring-boot-modules/spring-boot-2/pom.xml
+++ b/spring-boot-modules/spring-boot-2/pom.xml
@@ -63,7 +63,7 @@
2.14.1
- 5.3.13
+ 5.3.15
11
11
diff --git a/spring-boot-modules/spring-boot-actuator/README.md b/spring-boot-modules/spring-boot-actuator/README.md
index 59f7e929da..ea43377ed2 100644
--- a/spring-boot-modules/spring-boot-actuator/README.md
+++ b/spring-boot-modules/spring-boot-actuator/README.md
@@ -12,3 +12,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Health Indicators in Spring Boot](https://www.baeldung.com/spring-boot-health-indicators)
- [How to Enable All Endpoints in Spring Boot Actuator](https://www.baeldung.com/spring-boot-actuator-enable-endpoints)
- [Spring Boot Startup Actuator Endpoint](https://www.baeldung.com/spring-boot-actuator-startup)
+- [Metrics for your Spring REST API](https://www.baeldung.com/spring-rest-api-metrics)
diff --git a/spring-boot-modules/spring-boot-actuator/pom.xml b/spring-boot-modules/spring-boot-actuator/pom.xml
index b2c7a4d28e..1ccf436bbf 100644
--- a/spring-boot-modules/spring-boot-actuator/pom.xml
+++ b/spring-boot-modules/spring-boot-actuator/pom.xml
@@ -23,6 +23,10 @@
org.springframework.boot
spring-boot-starter-web
+
+ org.apache.tomcat.embed
+ tomcat-embed-jasper
+
org.springframework.boot
spring-boot-starter-data-jpa
@@ -35,6 +39,16 @@
com.h2database
h2
+
+ javax.servlet
+ javax.servlet-api
+ provided
+
+
+ javax.servlet
+ jstl
+ runtime
+
org.springframework.boot
spring-boot-starter-test
@@ -51,6 +65,10 @@
spring-security-test
test
+
+ org.awaitility
+ awaitility
+
diff --git a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/MetricsApplication.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/MetricsApplication.java
new file mode 100644
index 0000000000..729b3c0b96
--- /dev/null
+++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/MetricsApplication.java
@@ -0,0 +1,42 @@
+package com.baeldung.metrics;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration;
+import org.springframework.boot.actuate.autoconfigure.security.servlet.SecurityRequestMatchersManagementContextConfiguration;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
+import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
+import org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration;
+import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.web.context.request.RequestContextListener;
+
+import javax.servlet.ServletContext;
+
+@EnableScheduling
+@ComponentScan("com.baeldung.metrics")
+@SpringBootApplication
+public class MetricsApplication extends SpringBootServletInitializer {
+
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ return application.sources(MetricsApplication.class);
+ }
+
+ @Override
+ public void onStartup(ServletContext sc) {
+ // Manages the lifecycle of the root application context
+ sc.addListener(new RequestContextListener());
+ }
+
+ public static void main(final String[] args) {
+ // only load properties for this application
+ System.setProperty("spring.config.location", "classpath:application-metrics.properties");
+ SpringApplication.run(MetricsApplication.class, args);
+ }
+
+}
\ No newline at end of file
diff --git a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/spring/WebConfig.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/WebConfig.java
similarity index 81%
rename from spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/spring/WebConfig.java
rename to spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/WebConfig.java
index e35acb0bf0..4c38e4dbad 100644
--- a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/spring/WebConfig.java
+++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/WebConfig.java
@@ -1,4 +1,4 @@
-package com.baeldung.spring;
+package com.baeldung.metrics;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
@@ -10,14 +10,10 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
-@ComponentScan("com.baeldung.web")
+@ComponentScan("com.baeldung.metrics")
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
- public WebConfig() {
- super();
- }
-
@Bean
public ViewResolver viewResolver() {
final InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
@@ -26,11 +22,10 @@ public class WebConfig implements WebMvcConfigurer {
return viewResolver;
}
- // API
@Override
public void addViewControllers(final ViewControllerRegistry registry) {
- registry.addViewController("/graph.html");
- registry.addViewController("/homepage.html");
+ registry.addViewController("/metrics/graph.html");
+ registry.addViewController("/metrics/homepage.html");
}
}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/controller/MetricsController.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/controller/MetricsController.java
new file mode 100644
index 0000000000..e52ddd70f1
--- /dev/null
+++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/controller/MetricsController.java
@@ -0,0 +1,41 @@
+package com.baeldung.metrics.controller;
+
+import com.baeldung.metrics.service.InMemoryMetricService;
+import com.baeldung.metrics.service.MetricService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.Map;
+
+@Controller
+@RequestMapping(value = "/metrics")
+@ResponseBody
+public class MetricsController {
+
+ @Autowired
+ private InMemoryMetricService metricService;
+
+ // change the qualifier to use the in-memory implementation
+ @Autowired
+ @Qualifier("customActuatorMetricService")
+ private MetricService graphMetricService;
+
+ @GetMapping(value = "/metric")
+ public Map> getMetric() {
+ return metricService.getFullMetric();
+ }
+
+ @GetMapping(value = "/status-metric")
+ public Map getStatusMetric() {
+ return metricService.getStatusMetric();
+ }
+
+ @GetMapping(value = "/metric-graph-data")
+ public Object[][] getMetricData() {
+ return graphMetricService.getGraphData();
+ }
+}
diff --git a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/MetricFilter.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/filter/MetricFilter.java
similarity index 64%
rename from spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/MetricFilter.java
rename to spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/filter/MetricFilter.java
index dee63b226f..0f7579f060 100644
--- a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/MetricFilter.java
+++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/filter/MetricFilter.java
@@ -1,4 +1,11 @@
-package com.baeldung.web.metric;
+package com.baeldung.metrics.filter;
+
+import com.baeldung.metrics.service.CustomActuatorMetricService;
+import com.baeldung.metrics.service.InMemoryMetricService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
@@ -9,24 +16,23 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-import org.springframework.web.context.support.WebApplicationContextUtils;
-
@Component
public class MetricFilter implements Filter {
@Autowired
- private IMetricService metricService;
+ private InMemoryMetricService metricService;
@Autowired
- private ICustomActuatorMetricService actMetricService;
+ private CustomActuatorMetricService actMetricService;
@Override
- public void init(final FilterConfig config) throws ServletException {
+ public void init(final FilterConfig config) {
if (metricService == null || actMetricService == null) {
- metricService = (IMetricService) WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext()).getBean("metricService");
- actMetricService = WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext()).getBean(CustomActuatorMetricService.class);
+ WebApplicationContext appContext = WebApplicationContextUtils
+ .getRequiredWebApplicationContext(config.getServletContext());
+
+ metricService = appContext.getBean(InMemoryMetricService.class);
+ actMetricService = appContext.getBean(CustomActuatorMetricService.class);
}
}
@@ -42,8 +48,4 @@ public class MetricFilter implements Filter {
actMetricService.increaseCount(status);
}
- @Override
- public void destroy() {
-
- }
}
diff --git a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/ActuatorMetricService.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/service/ActuatorMetricService.java
similarity index 61%
rename from spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/ActuatorMetricService.java
rename to spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/service/ActuatorMetricService.java
index 8c26fa04a0..3eef265c02 100644
--- a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/ActuatorMetricService.java
+++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/service/ActuatorMetricService.java
@@ -1,32 +1,31 @@
-package com.baeldung.web.metric;
+package com.baeldung.metrics.service;
+
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.Meter;
+import io.micrometer.core.instrument.MeterRegistry;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Service;
-
-import io.micrometer.core.instrument.Counter;
-import io.micrometer.core.instrument.Meter;
-import io.micrometer.core.instrument.MeterRegistry;
-
@Service
-public class ActuatorMetricService implements IActuatorMetricService {
+public class ActuatorMetricService implements MetricService {
+
+ private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm");
@Autowired
private MeterRegistry publicMetrics;
- private final List> statusMetricsByMinute;
+ private final List> statusMetricsByMinute;
private final List statusList;
- private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
public ActuatorMetricService() {
- super();
- statusMetricsByMinute = new ArrayList>();
- statusList = new ArrayList();
+ statusMetricsByMinute = new ArrayList<>();
+ statusList = new ArrayList<>();
}
@Override
@@ -36,19 +35,19 @@ public class ActuatorMetricService implements IActuatorMetricService {
final int rowCount = statusMetricsByMinute.size() + 1;
final Object[][] result = new Object[rowCount][colCount];
result[0][0] = "Time";
- int j = 1;
+ int j = 1;
for (final String status : statusList) {
result[0][j] = status;
j++;
}
for (int i = 1; i < rowCount; i++) {
- result[i][0] = dateFormat.format(new Date(current.getTime() - (60000 * (rowCount - i))));
+ result[i][0] = DATE_FORMAT.format(new Date(current.getTime() - (60000L * (rowCount - i))));
}
List minuteOfStatuses;
- List last = new ArrayList();
+ List last = new ArrayList<>();
for (int i = 1; i < rowCount; i++) {
minuteOfStatuses = statusMetricsByMinute.get(i - 1);
@@ -64,11 +63,9 @@ public class ActuatorMetricService implements IActuatorMetricService {
return result;
}
- // Non - API
-
- @Scheduled(fixedDelay = 60000)
+ @Scheduled(fixedDelayString = "${fixedDelay.in.milliseconds:60000}")
private void exportMetrics() {
- final ArrayList lastMinuteStatuses = initializeStatuses(statusList.size());
+ final List lastMinuteStatuses = initializeStatuses(statusList.size());
for (final Meter counterMetric : publicMetrics.getMeters()) {
updateMetrics(counterMetric, lastMinuteStatuses);
@@ -77,34 +74,32 @@ public class ActuatorMetricService implements IActuatorMetricService {
statusMetricsByMinute.add(lastMinuteStatuses);
}
- private ArrayList initializeStatuses(final int size) {
- final ArrayList counterList = new ArrayList();
+ private List initializeStatuses(int size) {
+ List counterList = new ArrayList<>();
for (int i = 0; i < size; i++) {
counterList.add(0);
}
return counterList;
}
- private void updateMetrics(final Meter counterMetric, final ArrayList statusCount) {
- String status = "";
- int index = -1;
- int oldCount = 0;
+ private void updateMetrics(Meter counterMetric, List statusCount) {
- if (counterMetric.getId().getName().contains("counter.status.")) {
- status = counterMetric.getId().getName().substring(15, 18); // example 404, 200
+ String metricName = counterMetric.getId().getName();
+
+ if (metricName.contains("counter.status.")) {
+ // example 404, 200
+ String status = metricName.substring(15, 18);
appendStatusIfNotExist(status, statusCount);
- index = statusList.indexOf(status);
- oldCount = statusCount.get(index) == null ? 0 : statusCount.get(index);
+ int index = statusList.indexOf(status);
+ int oldCount = statusCount.get(index) == null ? 0 : statusCount.get(index);
statusCount.set(index, (int)((Counter) counterMetric).count() + oldCount);
}
}
- private void appendStatusIfNotExist(final String status, final ArrayList statusCount) {
+ private void appendStatusIfNotExist(String status, List statusCount) {
if (!statusList.contains(status)) {
statusList.add(status);
statusCount.add(0);
}
}
-
- //
-}
\ No newline at end of file
+}
diff --git a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/CustomActuatorMetricService.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/service/CustomActuatorMetricService.java
similarity index 68%
rename from spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/CustomActuatorMetricService.java
rename to spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/service/CustomActuatorMetricService.java
index ee17825b7c..9b4ccaa875 100644
--- a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/CustomActuatorMetricService.java
+++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/service/CustomActuatorMetricService.java
@@ -1,40 +1,36 @@
-package com.baeldung.web.metric;
+package com.baeldung.metrics.service;
+
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.search.Search;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Service;
-
-import io.micrometer.core.instrument.Counter;
-import io.micrometer.core.instrument.MeterRegistry;
-import io.micrometer.core.instrument.search.Search;
-
@Service
-public class CustomActuatorMetricService implements ICustomActuatorMetricService {
+public class CustomActuatorMetricService implements MetricService {
+
+ private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm");
@Autowired
private MeterRegistry registry;
- private final List> statusMetricsByMinute;
+ private final List> statusMetricsByMinute;
private final List statusList;
- private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
public CustomActuatorMetricService() {
- super();
- statusMetricsByMinute = new ArrayList>();
- statusList = new ArrayList();
+ statusMetricsByMinute = new ArrayList<>();
+ statusList = new ArrayList<>();
}
- // API
-
- @Override
- public void increaseCount(final int status) {
+ public void increaseCount(int status) {
String counterName = "counter.status." + status;
- registry.counter(counterName).increment(1);
+ registry.counter(counterName).increment();
if (!statusList.contains(counterName)) {
statusList.add(counterName);
}
@@ -55,7 +51,7 @@ public class CustomActuatorMetricService implements ICustomActuatorMetricService
}
for (int i = 1; i < rowCount; i++) {
- result[i][0] = dateFormat.format(new Date(current.getTime() - (60000 * (rowCount - i))));
+ result[i][0] = DATE_FORMAT.format(new Date(current.getTime() - (60000L * (rowCount - i))));
}
List minuteOfStatuses;
@@ -72,19 +68,17 @@ public class CustomActuatorMetricService implements ICustomActuatorMetricService
return result;
}
- // Non - API
-
- @Scheduled(fixedDelay = 60000)
+ @Scheduled(fixedDelayString = "${fixedDelay.in.milliseconds:60000}")
private void exportMetrics() {
- final ArrayList statusCount = new ArrayList();
+ List statusCount = new ArrayList<>();
for (final String status : statusList) {
Search search = registry.find(status);
- if (search != null) {
- Counter counter = search.counter();
- statusCount.add(counter != null ? ((int) counter.count()) : 0);
- registry.remove(counter);
- } else {
+ Counter counter = search.counter();
+ if (counter == null) {
statusCount.add(0);
+ } else {
+ statusCount.add((int) counter.count());
+ registry.remove(counter);
}
}
statusMetricsByMinute.add(statusCount);
diff --git a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/service/InMemoryMetricService.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/service/InMemoryMetricService.java
new file mode 100644
index 0000000000..0be5c21727
--- /dev/null
+++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/service/InMemoryMetricService.java
@@ -0,0 +1,112 @@
+package com.baeldung.metrics.service;
+
+import org.springframework.stereotype.Service;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Service
+public class InMemoryMetricService implements MetricService {
+
+ private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+
+ private final Map> metricMap;
+ private final Map statusMetric;
+ private final Map> timeMap;
+
+ public InMemoryMetricService() {
+ metricMap = new ConcurrentHashMap<>();
+ statusMetric = new ConcurrentHashMap<>();
+ timeMap = new ConcurrentHashMap<>();
+ }
+
+ public void increaseCount(String request, int status) {
+ increaseMainMetric(request, status);
+ increaseStatusMetric(status);
+ updateTimeMap(status);
+ }
+
+ public Map> getFullMetric() {
+ return metricMap;
+ }
+
+ public Map getStatusMetric() {
+ return statusMetric;
+ }
+
+ public Object[][] getGraphData() {
+ final int colCount = statusMetric.keySet().size() + 1;
+ final Set allStatus = statusMetric.keySet();
+ final int rowCount = timeMap.keySet().size() + 1;
+
+ final Object[][] result = new Object[rowCount][colCount];
+ result[0][0] = "Time";
+
+ int j = 1;
+ for (final int status : allStatus) {
+ result[0][j] = status;
+ j++;
+ }
+ int i = 1;
+ Map tempMap;
+ for (final Entry> entry : timeMap.entrySet()) {
+ result[i][0] = entry.getKey();
+ tempMap = entry.getValue();
+ for (j = 1; j < colCount; j++) {
+ result[i][j] = tempMap.get((Integer) result[0][j]);
+ if (result[i][j] == null) {
+ result[i][j] = 0;
+ }
+ }
+ i++;
+ }
+
+ for (int k = 1; k < result[0].length; k++) {
+ result[0][k] = result[0][k].toString();
+ }
+
+ return result;
+ }
+
+ private void increaseMainMetric(String request, int status) {
+ Map statusMap = metricMap.get(request);
+ if (statusMap == null) {
+ statusMap = new ConcurrentHashMap<>();
+ }
+
+ Integer count = statusMap.get(status);
+ if (count == null) {
+ count = 1;
+ } else {
+ count++;
+ }
+ statusMap.put(status, count);
+ metricMap.put(request, statusMap);
+ }
+
+ private void increaseStatusMetric(int status) {
+ statusMetric.merge(status, 1, Integer::sum);
+ }
+
+ private void updateTimeMap(int status) {
+ final String time = DATE_FORMAT.format(new Date());
+ Map statusMap = timeMap.get(time);
+ if (statusMap == null) {
+ statusMap = new ConcurrentHashMap<>();
+ }
+
+ Integer count = statusMap.get(status);
+ if (count == null) {
+ count = 1;
+ } else {
+ count++;
+ }
+ statusMap.put(status, count);
+ timeMap.put(time, statusMap);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/service/MetricService.java b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/service/MetricService.java
new file mode 100644
index 0000000000..3642102b67
--- /dev/null
+++ b/spring-boot-modules/spring-boot-actuator/src/main/java/com/baeldung/metrics/service/MetricService.java
@@ -0,0 +1,7 @@
+package com.baeldung.metrics.service;
+
+public interface MetricService {
+
+ Object[][] getGraphData();
+
+}
diff --git a/spring-boot-modules/spring-boot-actuator/src/main/resources/application-metrics.properties b/spring-boot-modules/spring-boot-actuator/src/main/resources/application-metrics.properties
new file mode 100644
index 0000000000..5f753a0c62
--- /dev/null
+++ b/spring-boot-modules/spring-boot-actuator/src/main/resources/application-metrics.properties
@@ -0,0 +1,9 @@
+management.endpoints.web.exposure.include=info,health,metrics
+
+# JPA and Security is not required for Metrics application
+spring.autoconfigure.exclude= org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, \
+ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, \
+ org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, \
+ org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration, \
+ org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration, \
+ org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration
diff --git a/spring-web-modules/spring-rest-testing/src/main/webapp/WEB-INF/api-servlet.xml b/spring-boot-modules/spring-boot-actuator/src/main/webapp/WEB-INF/api-servlet.xml
similarity index 100%
rename from spring-web-modules/spring-rest-testing/src/main/webapp/WEB-INF/api-servlet.xml
rename to spring-boot-modules/spring-boot-actuator/src/main/webapp/WEB-INF/api-servlet.xml
diff --git a/spring-web-modules/spring-rest-testing/src/main/webapp/WEB-INF/view/graph.jsp b/spring-boot-modules/spring-boot-actuator/src/main/webapp/WEB-INF/view/metrics/graph.jsp
similarity index 94%
rename from spring-web-modules/spring-rest-testing/src/main/webapp/WEB-INF/view/graph.jsp
rename to spring-boot-modules/spring-boot-actuator/src/main/webapp/WEB-INF/view/metrics/graph.jsp
index e1d5fdc987..75976557a0 100644
--- a/spring-web-modules/spring-rest-testing/src/main/webapp/WEB-INF/view/graph.jsp
+++ b/spring-boot-modules/spring-boot-actuator/src/main/webapp/WEB-INF/view/metrics/graph.jsp
@@ -11,7 +11,7 @@
});
function drawChart() {
- $.get("",
+ $.get("",
function(mydata) {
var data = google.visualization.arrayToDataTable(mydata);
diff --git a/spring-web-modules/spring-rest-testing/src/main/webapp/WEB-INF/view/homepage.jsp b/spring-boot-modules/spring-boot-actuator/src/main/webapp/WEB-INF/view/metrics/homepage.jsp
similarity index 100%
rename from spring-web-modules/spring-rest-testing/src/main/webapp/WEB-INF/view/homepage.jsp
rename to spring-boot-modules/spring-boot-actuator/src/main/webapp/WEB-INF/view/metrics/homepage.jsp
diff --git a/spring-web-modules/spring-rest-testing/src/main/webapp/WEB-INF/web.xml b/spring-boot-modules/spring-boot-actuator/src/main/webapp/WEB-INF/web.xml
similarity index 92%
rename from spring-web-modules/spring-rest-testing/src/main/webapp/WEB-INF/web.xml
rename to spring-boot-modules/spring-boot-actuator/src/main/webapp/WEB-INF/web.xml
index 7129b6b4af..84566ba93d 100644
--- a/spring-web-modules/spring-rest-testing/src/main/webapp/WEB-INF/web.xml
+++ b/spring-boot-modules/spring-boot-actuator/src/main/webapp/WEB-INF/web.xml
@@ -16,7 +16,7 @@
contextConfigLocation
- com.baeldung.spring
+ com.baeldung.metrics
@@ -37,7 +37,7 @@
metricFilter
- com.baeldung.web.metric.MetricFilter
+ com.baeldung.metrics.filter.MetricFilter
diff --git a/spring-boot-modules/spring-boot-actuator/src/test/java/com/baeldung/metrics/MetricsApplicationIntegrationTest.java b/spring-boot-modules/spring-boot-actuator/src/test/java/com/baeldung/metrics/MetricsApplicationIntegrationTest.java
new file mode 100644
index 0000000000..c83d4625dc
--- /dev/null
+++ b/spring-boot-modules/spring-boot-actuator/src/test/java/com/baeldung/metrics/MetricsApplicationIntegrationTest.java
@@ -0,0 +1,64 @@
+package com.baeldung.metrics;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.test.context.ActiveProfiles;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
+
+@SpringBootTest(
+ classes = MetricsApplication.class,
+ webEnvironment = RANDOM_PORT,
+ properties = {"fixedDelay.in.milliseconds=2000"}
+)
+@ActiveProfiles("metrics")
+class MetricsApplicationIntegrationTest {
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ @Test
+ void givenStatuses_WhenScheduledMethodExecuted_ExpectCountsAreAggregated() {
+ restTemplate.getForObject("/metrics/metric/notFound", String.class);
+ restTemplate.getForObject("/metrics/metric", String.class);
+
+ await().untilAsserted(() -> {
+ Object[][] statusCounts = restTemplate.getForObject("/metrics/metric-graph-data", Object[][].class);
+
+ assertThat(statusCounts[0]).contains("counter.status.200", "counter.status.404");
+
+ List requestCounts = getRequestCounts(statusCounts);
+ verify404RequestFrom(requestCounts);
+ verify200RequestsFrom(requestCounts);
+ });
+ }
+
+ private static void verify200RequestsFrom(List requestCounts) {
+ assertThat(requestCounts.size()).isGreaterThan(1);
+ }
+
+ private static void verify404RequestFrom(List requestCounts) {
+ assertThat(requestCounts).contains(1);
+ }
+
+ private static List getRequestCounts(Object[][] statusCounts) {
+ List requestCounts = new ArrayList<>();
+ for (int i = 1; i < statusCounts.length; i++) {
+ for (int j = 1; j < statusCounts[i].length; j++) {
+ Integer count = (Integer) statusCounts[i][j];
+ if (count >= 1) {
+ requestCounts.add(count);
+ }
+ }
+ }
+ return requestCounts;
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-artifacts/pom.xml b/spring-boot-modules/spring-boot-artifacts/pom.xml
index 6bf75491eb..0292dc95cf 100644
--- a/spring-boot-modules/spring-boot-artifacts/pom.xml
+++ b/spring-boot-modules/spring-boot-artifacts/pom.xml
@@ -101,7 +101,7 @@
maven-failsafe-plugin
2.18
-
integration-tests
@@ -110,7 +110,7 @@
verify
-
**/ExternalPropertyFileLoaderIntegrationTest.java
@@ -186,7 +186,7 @@
- com.baeldung.boot.Application
+ com.baeldung.wrapper.DemoApplication
3.1.1
3.3.7-1
2.2
@@ -195,4 +195,4 @@
4.5.8
-
\ No newline at end of file
+
diff --git a/spring-boot-modules/spring-boot-artifacts/src/main/java/com/baeldung/wrapper/DemoApplication.java b/spring-boot-modules/spring-boot-artifacts/src/main/java/com/baeldung/wrapper/DemoApplication.java
new file mode 100644
index 0000000000..d0a7e96bec
--- /dev/null
+++ b/spring-boot-modules/spring-boot-artifacts/src/main/java/com/baeldung/wrapper/DemoApplication.java
@@ -0,0 +1,12 @@
+package com.baeldung.wrapper;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication(scanBasePackages = { "com.baeldung" })
+public class DemoApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(DemoApplication.class, args);
+ }
+}
diff --git a/spring-boot-modules/spring-boot-artifacts/src/main/java/com/baeldung/wrapper/DemoController.java b/spring-boot-modules/spring-boot-artifacts/src/main/java/com/baeldung/wrapper/DemoController.java
new file mode 100644
index 0000000000..530a1d584e
--- /dev/null
+++ b/spring-boot-modules/spring-boot-artifacts/src/main/java/com/baeldung/wrapper/DemoController.java
@@ -0,0 +1,15 @@
+package com.baeldung.wrapper;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@Controller
+public class DemoController {
+
+ @GetMapping(value = "/demo")
+ public String demo(Model model) {
+ return "index";
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/noconverterfound/controller/StudentRestController.java b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/noconverterfound/controller/StudentRestController.java
index 21cb98710d..4119b624e1 100644
--- a/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/noconverterfound/controller/StudentRestController.java
+++ b/spring-boot-modules/spring-boot-data-2/src/main/java/com/baeldung/boot/noconverterfound/controller/StudentRestController.java
@@ -1,5 +1,6 @@
package com.baeldung.boot.noconverterfound.controller;
+import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -18,4 +19,14 @@ public class StudentRestController {
return ResponseEntity.ok(new Student(id, "John", "Wiliams", "AA"));
}
+ @GetMapping(value = "/student/v2/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity getV2(@PathVariable("id") int id) {
+ return ResponseEntity.ok(new Student(id, "Kevin", "Cruyff", "AA"));
+ }
+
+ @GetMapping(value = "/student/v3/{id}", produces = MediaType.APPLICATION_XML_VALUE)
+ public ResponseEntity getV3(@PathVariable("id") int id) {
+ return ResponseEntity.ok(new Student(id, "Robert", "Miller", "BB"));
+ }
+
}
diff --git a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/noconverterfound/NoConverterFoundIntegrationTest.java b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/noconverterfound/NoConverterFoundIntegrationTest.java
index f8ded91e65..6f89ef0e58 100644
--- a/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/noconverterfound/NoConverterFoundIntegrationTest.java
+++ b/spring-boot-modules/spring-boot-data-2/src/test/java/com/baeldung/boot/noconverterfound/NoConverterFoundIntegrationTest.java
@@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -25,16 +26,16 @@ public class NoConverterFoundIntegrationTest {
/* Remove Getters from Student class to successfully run this test case
* @Test
public void whenGettersNotDefined_thenThrowException() throws Exception {
-
+
String url = "/api/student/1";
-
+
this.mockMvc.perform(get(url))
.andExpect(status().isInternalServerError())
.andExpect(result -> assertThat(result.getResolvedException())
.isInstanceOf(HttpMessageNotWritableException.class))
.andExpect(result -> assertThat(result.getResolvedException().getMessage())
.contains("No converter found for return value of type"));
-
+
}
*/
@@ -44,9 +45,28 @@ public class NoConverterFoundIntegrationTest {
String url = "/api/student/2";
this.mockMvc.perform(get(url))
- .andExpect(status().isOk())
- .andExpect(jsonPath("$.firstName").value("John"));
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.firstName").value("John"));
+ }
+ @Test
+ public void whenJsonConverterIsFound_thenReturnResponse() throws Exception {
+ String url = "/api/student/v2/1";
+
+ this.mockMvc.perform(get(url))
+ .andExpect(status().isOk())
+ .andExpect(content().json("{'id':1,'firstName':'Kevin','lastName':'Cruyff', 'grade':'AA'}"));
+ }
+
+ @Test
+ public void whenConverterNotFound_thenThrowException() throws Exception {
+ String url = "/api/student/v3/1";
+
+ this.mockMvc.perform(get(url))
+ .andExpect(status().isInternalServerError())
+ .andExpect(result -> assertThat(result.getResolvedException()).isInstanceOf(HttpMessageNotWritableException.class))
+ .andExpect(result -> assertThat(result.getResolvedException()
+ .getMessage()).contains("No converter for [class com.baeldung.boot.noconverterfound.model.Student] with preset Content-Type"));
}
}
diff --git a/spring-boot-modules/spring-boot-multiple-datasources/.gitignore b/spring-boot-modules/spring-boot-multiple-datasources/.gitignore
new file mode 100644
index 0000000000..87a3fce287
--- /dev/null
+++ b/spring-boot-modules/spring-boot-multiple-datasources/.gitignore
@@ -0,0 +1 @@
+.local-db
diff --git a/spring-boot-modules/spring-boot-multiple-datasources/pom.xml b/spring-boot-modules/spring-boot-multiple-datasources/pom.xml
new file mode 100644
index 0000000000..d66095bc2c
--- /dev/null
+++ b/spring-boot-modules/spring-boot-multiple-datasources/pom.xml
@@ -0,0 +1,58 @@
+
+
+ 4.0.0
+ spring-boot-multiple-datasources
+ 0.1.0-SNAPSHOT
+ spring-boot-multiple-datasources
+ jar
+ Module For Spring Boot With Multiple Datasources
+
+
+ com.baeldung.spring-boot-modules
+ spring-boot-modules
+ 1.0.0-SNAPSHOT
+ ../pom.xml
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ com.h2database
+ h2
+ provided
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+ 2.6.3
+
+
+
diff --git a/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/MultipleDatasourcesApplication.java b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/MultipleDatasourcesApplication.java
new file mode 100644
index 0000000000..efdff387df
--- /dev/null
+++ b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/MultipleDatasourcesApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.spring.datasources;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class MultipleDatasourcesApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(MultipleDatasourcesApplication.class, args);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/todos/Todo.java b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/todos/Todo.java
new file mode 100644
index 0000000000..6f8557e258
--- /dev/null
+++ b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/todos/Todo.java
@@ -0,0 +1,48 @@
+package com.baeldung.spring.datasources.todos;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class Todo {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private Long id;
+ private String title;
+ private boolean completed;
+
+ public Todo() {
+ }
+
+ public Todo(String title) {
+ this.title = title;
+ }
+
+ 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 boolean isCompleted() {
+ return completed;
+ }
+
+ public void setCompleted(boolean completed) {
+ this.completed = completed;
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/todos/TodoDatasourceConfiguration.java b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/todos/TodoDatasourceConfiguration.java
new file mode 100644
index 0000000000..3bfc8e2855
--- /dev/null
+++ b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/todos/TodoDatasourceConfiguration.java
@@ -0,0 +1,28 @@
+package com.baeldung.spring.datasources.todos;
+
+import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+
+import javax.sql.DataSource;
+
+@Configuration
+public class TodoDatasourceConfiguration {
+
+ @Bean
+ @ConfigurationProperties("spring.datasource.todos")
+ public DataSourceProperties todosDataSourceProperties() {
+ return new DataSourceProperties();
+ }
+
+ @Bean
+ @Primary
+ public DataSource todosDataSource() {
+ return todosDataSourceProperties()
+ .initializeDataSourceBuilder()
+ .build();
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/todos/TodoJpaConfiguration.java b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/todos/TodoJpaConfiguration.java
new file mode 100644
index 0000000000..655a3a55c2
--- /dev/null
+++ b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/todos/TodoJpaConfiguration.java
@@ -0,0 +1,40 @@
+package com.baeldung.spring.datasources.todos;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.orm.jpa.JpaTransactionManager;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+import javax.sql.DataSource;
+import java.util.Objects;
+
+@Configuration
+@EnableTransactionManagement
+@EnableJpaRepositories(
+ basePackageClasses = Todo.class,
+ entityManagerFactoryRef = "todosEntityManagerFactory",
+ transactionManagerRef = "todosTransactionManager"
+)
+public class TodoJpaConfiguration {
+
+ @Bean
+ public LocalContainerEntityManagerFactoryBean todosEntityManagerFactory(
+ @Qualifier("todosDataSource") DataSource dataSource,
+ EntityManagerFactoryBuilder builder) {
+ return builder
+ .dataSource(dataSource)
+ .packages(Todo.class)
+ .build();
+ }
+
+ @Bean
+ public PlatformTransactionManager todosTransactionManager(
+ @Qualifier("todosEntityManagerFactory") LocalContainerEntityManagerFactoryBean todosEntityManagerFactory) {
+ return new JpaTransactionManager(Objects.requireNonNull(todosEntityManagerFactory.getObject()));
+ }
+}
diff --git a/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/todos/TodoRepository.java b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/todos/TodoRepository.java
new file mode 100644
index 0000000000..09fb8c6500
--- /dev/null
+++ b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/todos/TodoRepository.java
@@ -0,0 +1,6 @@
+package com.baeldung.spring.datasources.todos;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface TodoRepository extends JpaRepository {
+}
diff --git a/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/topics/Topic.java b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/topics/Topic.java
new file mode 100644
index 0000000000..1d1f20f111
--- /dev/null
+++ b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/topics/Topic.java
@@ -0,0 +1,39 @@
+package com.baeldung.spring.datasources.topics;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class Topic {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private Long id;
+ private String title;
+
+ public Topic() {
+ }
+
+ public Topic(String title) {
+ this.title = title;
+ }
+
+ 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;
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/topics/TopicDatasourceConfiguration.java b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/topics/TopicDatasourceConfiguration.java
new file mode 100644
index 0000000000..a06983d681
--- /dev/null
+++ b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/topics/TopicDatasourceConfiguration.java
@@ -0,0 +1,26 @@
+package com.baeldung.spring.datasources.topics;
+
+import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.sql.DataSource;
+
+@Configuration
+public class TopicDatasourceConfiguration {
+
+ @Bean
+ @ConfigurationProperties("spring.datasource.topics")
+ public DataSourceProperties topicsDataSourceProperties() {
+ return new DataSourceProperties();
+ }
+
+ @Bean
+ public DataSource topicsDataSource() {
+ return topicsDataSourceProperties()
+ .initializeDataSourceBuilder()
+ .build();
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/topics/TopicJpaConfiguration.java b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/topics/TopicJpaConfiguration.java
new file mode 100644
index 0000000000..d800813b8c
--- /dev/null
+++ b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/topics/TopicJpaConfiguration.java
@@ -0,0 +1,41 @@
+package com.baeldung.spring.datasources.topics;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.orm.jpa.JpaTransactionManager;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+import javax.sql.DataSource;
+import java.util.Objects;
+
+@Configuration
+@EnableTransactionManagement
+@EnableJpaRepositories(
+ basePackageClasses = Topic.class,
+ entityManagerFactoryRef = "topicsEntityManagerFactory",
+ transactionManagerRef = "topicsTransactionManager"
+)
+public class TopicJpaConfiguration {
+
+ @Bean
+ public LocalContainerEntityManagerFactoryBean topicsEntityManagerFactory(
+ @Qualifier("topicsDataSource") DataSource dataSource,
+ EntityManagerFactoryBuilder builder
+ ) {
+ return builder
+ .dataSource(dataSource)
+ .packages(Topic.class)
+ .build();
+ }
+
+ @Bean
+ public PlatformTransactionManager topicsTransactionManager(
+ @Qualifier("topicsEntityManagerFactory") LocalContainerEntityManagerFactoryBean topicsEntityManagerFactory) {
+ return new JpaTransactionManager(Objects.requireNonNull(topicsEntityManagerFactory.getObject()));
+ }
+}
diff --git a/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/topics/TopicRepository.java b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/topics/TopicRepository.java
new file mode 100644
index 0000000000..499b72650a
--- /dev/null
+++ b/spring-boot-modules/spring-boot-multiple-datasources/src/main/java/com/baeldung/spring/datasources/topics/TopicRepository.java
@@ -0,0 +1,6 @@
+package com.baeldung.spring.datasources.topics;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface TopicRepository extends JpaRepository {
+}
diff --git a/spring-boot-modules/spring-boot-multiple-datasources/src/main/resources/application.yml b/spring-boot-modules/spring-boot-multiple-datasources/src/main/resources/application.yml
new file mode 100644
index 0000000000..4754acfc0f
--- /dev/null
+++ b/spring-boot-modules/spring-boot-multiple-datasources/src/main/resources/application.yml
@@ -0,0 +1,23 @@
+spring:
+ datasource:
+ todos:
+ url: jdbc:h2:./.local-db/todos;DB_CLOSE_DELAY=-1;MODE=DB2;AUTO_SERVER=TRUE
+ username: sa
+ password: null
+ driverClassName: org.h2.Driver
+ topics:
+ url: jdbc:h2:./.local-db/topics;DB_CLOSE_DELAY=-1;MODE=DB2;AUTO_SERVER=TRUE
+ username: sa
+ password: null
+ driverClassName: org.h2.Driver
+ h2:
+ console:
+ enabled: true
+ path: /h2-console
+ jpa:
+ generate-ddl: true
+ hibernate:
+ ddl-auto: update
+ properties:
+ hibernate:
+ dialect: org.hibernate.dialect.H2Dialect
diff --git a/spring-boot-modules/spring-boot-multiple-datasources/src/test/java/com/baeldung/spring/datasources/MultipleDatasourcesIntegrationTest.java b/spring-boot-modules/spring-boot-multiple-datasources/src/test/java/com/baeldung/spring/datasources/MultipleDatasourcesIntegrationTest.java
new file mode 100644
index 0000000000..397992f6c8
--- /dev/null
+++ b/spring-boot-modules/spring-boot-multiple-datasources/src/test/java/com/baeldung/spring/datasources/MultipleDatasourcesIntegrationTest.java
@@ -0,0 +1,39 @@
+package com.baeldung.spring.datasources;
+
+import com.baeldung.spring.datasources.todos.Todo;
+import com.baeldung.spring.datasources.todos.TodoRepository;
+import com.baeldung.spring.datasources.topics.Topic;
+import com.baeldung.spring.datasources.topics.TopicRepository;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+
+import java.util.Optional;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@DataJpaTest // no test database!
+class MultipleDatasourcesIntegrationTest {
+
+ @Autowired
+ TodoRepository todoRepo;
+ @Autowired
+ TopicRepository topicRepo;
+
+ @Test
+ void shouldSaveTodoToTodoDB() {
+ Todo todo = new Todo("test");
+ Todo saved =todoRepo.save(todo);
+ Optional result= todoRepo.findById(saved.getId());
+ assertThat(result).isPresent();
+ }
+
+ @Test
+ void shouldSaveTopicToTopicDB() {
+ Topic todo = new Topic("test");
+ Topic saved =topicRepo.save(todo);
+ Optional result= topicRepo.findById(saved.getId());
+ assertThat(result).isPresent();
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/SpringBootSwaggerConfApplication.java b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/SpringBootSwaggerConfApplication.java
new file mode 100644
index 0000000000..1d2e129f26
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/SpringBootSwaggerConfApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.swaggerconf;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SpringBootSwaggerConfApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SpringBootSwaggerConfApplication.class, args);
+ }
+
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/configuration/SwaggerConfiguration.java b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/configuration/SwaggerConfiguration.java
new file mode 100644
index 0000000000..a78335a2fe
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/configuration/SwaggerConfiguration.java
@@ -0,0 +1,37 @@
+package com.baeldung.swaggerconf.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.bind.annotation.RestController;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import java.util.Collections;
+
+import static springfox.documentation.builders.PathSelectors.regex;
+
+@Configuration
+@EnableSwagger2
+public class SwaggerConfiguration {
+
+ private ApiInfo apiInfo() {
+ return new ApiInfo("My REST API", "Some custom description of API.", "API TOS", "Terms of service",
+ new Contact("General UserName", "www.baeldung.com", "user-name@gmail.com"),
+ "License of API", "API license URL", Collections.emptyList());
+ }
+
+ @Bean
+ public Docket api() {
+ return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
+ .select()
+ .apis(RequestHandlerSelectors.basePackage("com.baeldung.swaggerconf.controller"))
+ .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
+ .paths(regex("/good-path/.*"))
+ .build();
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/controller/ErrorControllerExcludedForAnnotation.java b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/controller/ErrorControllerExcludedForAnnotation.java
new file mode 100644
index 0000000000..65059bf446
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/controller/ErrorControllerExcludedForAnnotation.java
@@ -0,0 +1,17 @@
+package com.baeldung.swaggerconf.controller;
+
+import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
+import org.springframework.boot.web.servlet.error.ErrorAttributes;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@Component
+@RequestMapping("good-path/error-excluded-annotation")
+public class ErrorControllerExcludedForAnnotation extends BasicErrorController {
+
+ public ErrorControllerExcludedForAnnotation(ErrorAttributes errorAttributes, ServerProperties serverProperties) {
+ super(errorAttributes, serverProperties.getError());
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/controller/ErrorControllerExcludedForApiIgnore.java b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/controller/ErrorControllerExcludedForApiIgnore.java
new file mode 100644
index 0000000000..88208d8446
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/controller/ErrorControllerExcludedForApiIgnore.java
@@ -0,0 +1,21 @@
+package com.baeldung.swaggerconf.controller;
+
+import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
+import org.springframework.boot.web.servlet.error.ErrorAttributes;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import springfox.documentation.annotations.ApiIgnore;
+
+@Component
+@RequestMapping("good-path/error-excluded-apiignore")
+@RestController
+@ApiIgnore
+public class ErrorControllerExcludedForApiIgnore extends BasicErrorController {
+
+ public ErrorControllerExcludedForApiIgnore(ErrorAttributes errorAttributes, ServerProperties serverProperties) {
+ super(errorAttributes, serverProperties.getError());
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/controller/ErrorControllerExcludedForPath.java b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/controller/ErrorControllerExcludedForPath.java
new file mode 100644
index 0000000000..5cea4f5ef9
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/controller/ErrorControllerExcludedForPath.java
@@ -0,0 +1,19 @@
+package com.baeldung.swaggerconf.controller;
+
+import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
+import org.springframework.boot.web.servlet.error.ErrorAttributes;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@Component
+@RequestMapping("wrong-path/error-excluded-path")
+@RestController
+public class ErrorControllerExcludedForPath extends BasicErrorController {
+
+ public ErrorControllerExcludedForPath(ErrorAttributes errorAttributes, ServerProperties serverProperties) {
+ super(errorAttributes, serverProperties.getError());
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/controller/RegularRestController.java b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/controller/RegularRestController.java
new file mode 100644
index 0000000000..163826e626
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/controller/RegularRestController.java
@@ -0,0 +1,33 @@
+package com.baeldung.swaggerconf.controller;
+
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+
+@RestController
+@RequestMapping("good-path")
+public class RegularRestController {
+
+ @ApiOperation(value = "This method is used to get the author name.")
+ @GetMapping("/getAuthor")
+ public String getAuthor() {
+ return "Name Surname";
+ }
+
+ @ApiOperation(value = "This method is used to get the current date.")
+ @GetMapping("/getDate")
+ public LocalDate getDate() {
+ return LocalDate.now();
+ }
+
+ @ApiOperation(value = "This method is used to get the current time.")
+ @GetMapping("/getTime")
+ public LocalTime getTime() {
+ return LocalTime.now();
+ }
+
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/excluded/ErrorControllerExcludedForPackage.java b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/excluded/ErrorControllerExcludedForPackage.java
new file mode 100644
index 0000000000..a3b5a3fe63
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerconf/excluded/ErrorControllerExcludedForPackage.java
@@ -0,0 +1,17 @@
+package com.baeldung.swaggerconf.excluded;
+
+import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
+import org.springframework.boot.web.servlet.error.ErrorAttributes;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@Component
+@RequestMapping("good-path/error-excluded-package")
+public class ErrorControllerExcludedForPackage extends BasicErrorController {
+
+ public ErrorControllerExcludedForPackage(ErrorAttributes errorAttributes, ServerProperties serverProperties) {
+ super(errorAttributes, serverProperties.getError());
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerexample/SwaggerExampleApplication.java b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerexample/SwaggerExampleApplication.java
new file mode 100644
index 0000000000..4859224bb2
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerexample/SwaggerExampleApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.swaggerexample;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SwaggerExampleApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SwaggerExampleApplication.class, args);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerexample/config/SwaggerConfig.java b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerexample/config/SwaggerConfig.java
new file mode 100644
index 0000000000..32dbe87bae
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerexample/config/SwaggerConfig.java
@@ -0,0 +1,38 @@
+package com.baeldung.swaggerexample.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+
+import java.util.Collections;
+
+@Configuration
+@EnableWebMvc
+public class SwaggerConfig {
+
+ @Bean
+ public Docket api() {
+ return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
+ .select()
+ .apis(RequestHandlerSelectors.basePackage("com.baeldung.swaggerexample"))
+ .paths(PathSelectors.any())
+ .build();
+ }
+
+ private ApiInfo apiInfo() {
+ return new ApiInfo(
+ "Products API",
+ "API to let you add and view product",
+ "0.0.1",
+ "Terms of service",
+ new Contact("John Doe", "www.example.com", "myemail@company.com"),
+ "License of API", "API license URL", Collections.emptyList());
+ }
+}
diff --git a/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerexample/controller/ProductController.java b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerexample/controller/ProductController.java
new file mode 100644
index 0000000000..7500c01bc0
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerexample/controller/ProductController.java
@@ -0,0 +1,34 @@
+package com.baeldung.swaggerexample.controller;
+
+import com.baeldung.swaggerexample.entity.Product;
+import io.swagger.annotations.*;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@ApiOperation("Products API")
+public class ProductController {
+
+ @ApiOperation(value = "Create a new product", notes = "Creates a new product as per the request body")
+ @ApiResponses(value = {
+ @ApiResponse(code = 201, message = "Successfully created"),
+ @ApiResponse(code = 400, message = "Bad request - The product is not valid"),
+ @ApiResponse(code = 500, message = "Internal server error - Something went wrong")
+ })
+ @PostMapping(value = "/products")
+ public ResponseEntity createProduct(@RequestBody Product product) {
+ return new ResponseEntity<>(HttpStatus.CREATED);
+ }
+
+ @ApiOperation(value = "Get a product by id", notes = "Returns a product as per the id")
+ @ApiResponses(value = {
+ @ApiResponse(code = 200, message = "Successfully retrieved"),
+ @ApiResponse(code = 404, message = "Not found - The product was not found")
+ })
+ @GetMapping("/products/{id}")
+ public ResponseEntity getProduct(@PathVariable("id") @ApiParam(name = "id", value = "Product id", example = "1") Long id) {
+ //retrieval logic
+ return ResponseEntity.ok(new Product(1, "Product 1", "$21.99"));
+ }
+}
diff --git a/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerexample/entity/Product.java b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerexample/entity/Product.java
new file mode 100644
index 0000000000..122addadd5
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger/src/main/java/com/baeldung/swaggerexample/entity/Product.java
@@ -0,0 +1,46 @@
+package com.baeldung.swaggerexample.entity;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+
+public class Product implements Serializable {
+ @ApiModelProperty(notes = "Product ID", example = "1", required = true)
+ private Long id;
+ @ApiModelProperty(notes = "Product name", example = "Product 1", required = false)
+ private String name;
+ @ApiModelProperty(notes = "Product price", example = "$100.00", required = true)
+ private String price;
+
+ // constructor and getter/setters
+
+ public Product(long id, String name, String price) {
+ this.id = id;
+ this.name = name;
+ this.price = price;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getPrice() {
+ return price;
+ }
+
+ public void setPrice(String price) {
+ this.price = price;
+ }
+}
diff --git a/spring-boot-modules/spring-boot-swagger/src/main/resources/application.properties b/spring-boot-modules/spring-boot-swagger/src/main/resources/application.properties
index e69de29bb2..a4e98652bc 100644
--- a/spring-boot-modules/spring-boot-swagger/src/main/resources/application.properties
+++ b/spring-boot-modules/spring-boot-swagger/src/main/resources/application.properties
@@ -0,0 +1 @@
+spring.mvc.pathmatch.matching-strategy = ANT_PATH_MATCHER
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-swagger/src/test/java/com/baeldung/swaggerconf/SwaggerConfExcludeErrorControllerIntegrationTest.java b/spring-boot-modules/spring-boot-swagger/src/test/java/com/baeldung/swaggerconf/SwaggerConfExcludeErrorControllerIntegrationTest.java
new file mode 100644
index 0000000000..c0a5c54d69
--- /dev/null
+++ b/spring-boot-modules/spring-boot-swagger/src/test/java/com/baeldung/swaggerconf/SwaggerConfExcludeErrorControllerIntegrationTest.java
@@ -0,0 +1,33 @@
+package com.baeldung.swaggerconf;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.ResultActions;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@AutoConfigureMockMvc
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+public class SwaggerConfExcludeErrorControllerIntegrationTest {
+
+ @Autowired
+ private MockMvc mvc;
+
+ @Test
+ public void whenCallingSwaggerJSON_stringObjectDoesNotContainAnyErrorControllers() throws Exception {
+ ResultActions resultActions = mvc.perform(get("/v2/api-docs")).andExpect(status().isOk());
+ MvcResult result = resultActions.andReturn();
+ String content = result.getResponse().getContentAsString();
+ Assert.assertNotNull(content);
+ Assert.assertFalse(content.contains("error-controller"));
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-gateway/README.md b/spring-cloud/spring-cloud-gateway/README.md
index 90e81fe9a2..6b199977e3 100644
--- a/spring-cloud/spring-cloud-gateway/README.md
+++ b/spring-cloud/spring-cloud-gateway/README.md
@@ -3,7 +3,9 @@
This module contains articles about Spring Cloud Gateway
### Relevant Articles:
+
- [Exploring the new Spring Cloud Gateway](http://www.baeldung.com/spring-cloud-gateway)
- [Writing Custom Spring Cloud Gateway Filters](https://www.baeldung.com/spring-cloud-custom-gateway-filters)
- [Spring Cloud Gateway Routing Predicate Factories](https://www.baeldung.com/spring-cloud-gateway-routing-predicate-factories)
- [Spring Cloud Gateway WebFilter Factories](https://www.baeldung.com/spring-cloud-gateway-webfilter-factories)
+- [Using Spring Cloud Gateway with OAuth 2.0 Patterns](https://www.baeldung.com/spring-cloud-gateway-oauth2)
diff --git a/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceIntegrationTest.java b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceIntegrationTest.java
index 6b2a432d20..f4b3d0f00d 100644
--- a/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceIntegrationTest.java
+++ b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/customfilters/secondservice/SecondServiceIntegrationTest.java
@@ -2,12 +2,14 @@ package com.baeldung.springcloudgateway.customfilters.secondservice;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.test.web.reactive.server.WebTestClient;
import com.baeldung.springcloudgateway.customfilters.secondservice.web.SecondServiceRestController;
-@WebFluxTest(SecondServiceRestController.class)
+@WebFluxTest(controllers = SecondServiceRestController.class,
+ excludeAutoConfiguration = ReactiveSecurityAutoConfiguration.class)
public class SecondServiceIntegrationTest {
@Autowired
diff --git a/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/customfilters/service/ServiceIntegrationTest.java b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/customfilters/service/ServiceIntegrationTest.java
index bfb3f23f0d..9990cd003c 100644
--- a/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/customfilters/service/ServiceIntegrationTest.java
+++ b/spring-cloud/spring-cloud-gateway/src/test/java/com/baeldung/springcloudgateway/customfilters/service/ServiceIntegrationTest.java
@@ -2,13 +2,15 @@ package com.baeldung.springcloudgateway.customfilters.service;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.http.HttpHeaders;
import org.springframework.test.web.reactive.server.WebTestClient;
import com.baeldung.springcloudgateway.customfilters.service.web.ServiceRestController;
-@WebFluxTest(ServiceRestController.class)
+@WebFluxTest(controllers = ServiceRestController.class,
+ excludeAutoConfiguration = ReactiveSecurityAutoConfiguration.class)
public class ServiceIntegrationTest {
@Autowired
diff --git a/spring-cloud/spring-cloud-zuul/spring-zuul-ui/src/main/java/com/baeldung/spring/cloud/zuul/filter/CustomZuulErrorApplication.java b/spring-cloud/spring-cloud-zuul/spring-zuul-ui/src/main/java/com/baeldung/spring/cloud/zuul/filter/CustomZuulErrorApplication.java
new file mode 100644
index 0000000000..ae8c3040ef
--- /dev/null
+++ b/spring-cloud/spring-cloud-zuul/spring-zuul-ui/src/main/java/com/baeldung/spring/cloud/zuul/filter/CustomZuulErrorApplication.java
@@ -0,0 +1,15 @@
+package com.baeldung.spring.cloud.zuul.filter;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
+
+@EnableZuulProxy
+@SpringBootApplication
+public class CustomZuulErrorApplication extends SpringBootServletInitializer {
+
+ public static void main(String[] args) {
+ SpringApplication.run(CustomZuulErrorApplication.class, args);
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-zuul/spring-zuul-ui/src/main/java/com/baeldung/spring/cloud/zuul/filter/CustomZuulErrorFilter.java b/spring-cloud/spring-cloud-zuul/spring-zuul-ui/src/main/java/com/baeldung/spring/cloud/zuul/filter/CustomZuulErrorFilter.java
new file mode 100644
index 0000000000..d3e52843eb
--- /dev/null
+++ b/spring-cloud/spring-cloud-zuul/spring-zuul-ui/src/main/java/com/baeldung/spring/cloud/zuul/filter/CustomZuulErrorFilter.java
@@ -0,0 +1,62 @@
+package com.baeldung.spring.cloud.zuul.filter;
+
+import java.net.ConnectException;
+import java.time.Instant;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import com.netflix.zuul.ZuulFilter;
+import com.netflix.zuul.context.RequestContext;
+import com.netflix.zuul.exception.ZuulException;
+
+@Component
+public class CustomZuulErrorFilter extends ZuulFilter {
+
+ private static final Logger log = LoggerFactory.getLogger(CustomZuulErrorFilter.class);
+
+ private static final String RESPONSE_BODY = "{\n" + " \"timestamp\": " + "\"" + Instant.now()
+ .toString() + "\"" + ",\n" + " \"status\": 503,\n" + " \"error\": \"Service Unavailable\"\n" + "}";
+
+ @Override
+ public Object run() {
+ RequestContext context = RequestContext.getCurrentContext();
+ Throwable throwable = context.getThrowable();
+
+ if (throwable instanceof ZuulException) {
+ final ZuulException zuulException = (ZuulException) throwable;
+ log.error("Zuul exception: " + zuulException.getMessage());
+
+ if (throwable.getCause().getCause().getCause() instanceof ConnectException) {
+
+ // reset throwable to prevent further error handling in follow up filters
+ context.remove("throwable");
+
+ // set custom response attributes
+ context.setResponseBody(RESPONSE_BODY);
+ context.getResponse()
+ .setContentType("application/json");
+ context.setResponseStatusCode(503);
+ }
+
+ }
+ return null;
+ }
+
+ @Override
+ public boolean shouldFilter() {
+ return true;
+ }
+
+ @Override
+ public int filterOrder() {
+ return -1;
+ }
+
+ @Override
+ public String filterType() {
+ return "error";
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-zuul/spring-zuul-ui/src/main/java/com/baeldung/spring/cloud/zuul/filter/ZuulConfiguration.java b/spring-cloud/spring-cloud-zuul/spring-zuul-ui/src/main/java/com/baeldung/spring/cloud/zuul/filter/ZuulConfiguration.java
new file mode 100644
index 0000000000..3122862050
--- /dev/null
+++ b/spring-cloud/spring-cloud-zuul/spring-zuul-ui/src/main/java/com/baeldung/spring/cloud/zuul/filter/ZuulConfiguration.java
@@ -0,0 +1,98 @@
+package com.baeldung.spring.cloud.zuul.filter;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.boot.web.servlet.error.ErrorController;
+import org.springframework.cglib.proxy.Callback;
+import org.springframework.cglib.proxy.CallbackFilter;
+import org.springframework.cglib.proxy.Enhancer;
+import org.springframework.cglib.proxy.MethodInterceptor;
+import org.springframework.cglib.proxy.MethodProxy;
+import org.springframework.cglib.proxy.NoOp;
+import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
+import org.springframework.cloud.netflix.zuul.web.ZuulController;
+import org.springframework.cloud.netflix.zuul.web.ZuulHandlerMapping;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Fix for Zuul configuration with Spring Boot 2.5.x + Zuul - "NoSuchMethodError: ErrorController.getErrorPath()":
+ */
+@Configuration
+public class ZuulConfiguration {
+ /**
+ * The path returned by ErrorController.getErrorPath() with Spring Boot < 2.5
+ * (and no longer available on Spring Boot >= 2.5).
+ */
+ private static final String ERROR_PATH = "/error";
+ private static final String METHOD = "lookupHandler";
+
+ /**
+ * Constructs a new bean post-processor for Zuul.
+ *
+ * @param routeLocator the route locator.
+ * @param zuulController the Zuul controller.
+ * @param errorController the error controller.
+ * @return the new bean post-processor.
+ */
+ @Bean
+ public ZuulPostProcessor zuulPostProcessor(@Autowired RouteLocator routeLocator, @Autowired ZuulController zuulController, @Autowired(required = false) ErrorController errorController) {
+ return new ZuulPostProcessor(routeLocator, zuulController, errorController);
+ }
+
+ private enum LookupHandlerCallbackFilter implements CallbackFilter {
+ INSTANCE;
+
+ @Override
+ public int accept(Method method) {
+ if (METHOD.equals(method.getName())) {
+ return 0;
+ }
+ return 1;
+ }
+ }
+
+ private enum LookupHandlerMethodInterceptor implements MethodInterceptor {
+ INSTANCE;
+
+ @Override
+ public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
+ if (ERROR_PATH.equals(args[0])) {
+ // by entering this branch we avoid the ZuulHandlerMapping.lookupHandler method to trigger the
+ // NoSuchMethodError
+ return null;
+ }
+ return methodProxy.invokeSuper(target, args);
+ }
+ }
+
+ private static final class ZuulPostProcessor implements BeanPostProcessor {
+
+ private final RouteLocator routeLocator;
+ private final ZuulController zuulController;
+ private final boolean hasErrorController;
+
+ ZuulPostProcessor(RouteLocator routeLocator, ZuulController zuulController, ErrorController errorController) {
+ this.routeLocator = routeLocator;
+ this.zuulController = zuulController;
+ this.hasErrorController = (errorController != null);
+ }
+
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+ if (hasErrorController && (bean instanceof ZuulHandlerMapping)) {
+ Enhancer enhancer = new Enhancer();
+ enhancer.setSuperclass(ZuulHandlerMapping.class);
+ enhancer.setCallbackFilter(LookupHandlerCallbackFilter.INSTANCE); // only for lookupHandler
+ enhancer.setCallbacks(new Callback[] { LookupHandlerMethodInterceptor.INSTANCE, NoOp.INSTANCE });
+ Constructor> ctor = ZuulHandlerMapping.class.getConstructors()[0];
+ return enhancer.create(ctor.getParameterTypes(), new Object[] { routeLocator, zuulController });
+ }
+ return bean;
+ }
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-zuul/spring-zuul-ui/src/main/resources/application.yml b/spring-cloud/spring-cloud-zuul/spring-zuul-ui/src/main/resources/application.yml
index 855020a40e..bd517b8a6b 100644
--- a/spring-cloud/spring-cloud-zuul/spring-zuul-ui/src/main/resources/application.yml
+++ b/spring-cloud/spring-cloud-zuul/spring-zuul-ui/src/main/resources/application.yml
@@ -1,5 +1,8 @@
zuul:
+ SendErrorFilter:
+ post:
+ disable: true
routes:
foos:
path: /foos/**
- url: http://localhost:8081/spring-zuul-foos-resource/foos
+ url: http://localhost:8081/spring-zuul-foos-resource/foos
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-zuul/spring-zuul-ui/src/test/java/com/baeldung/spring/cloud/zuul/filter/CustomZuulErrorFilterLiveTest.java b/spring-cloud/spring-cloud-zuul/spring-zuul-ui/src/test/java/com/baeldung/spring/cloud/zuul/filter/CustomZuulErrorFilterLiveTest.java
new file mode 100644
index 0000000000..da2588966d
--- /dev/null
+++ b/spring-cloud/spring-cloud-zuul/spring-zuul-ui/src/test/java/com/baeldung/spring/cloud/zuul/filter/CustomZuulErrorFilterLiveTest.java
@@ -0,0 +1,24 @@
+package com.baeldung.spring.cloud.zuul.filter;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import io.restassured.RestAssured;
+import io.restassured.response.Response;
+
+public class CustomZuulErrorFilterLiveTest {
+
+ @Test
+ public void whenSendRequestWithoutService_thenCustomError() {
+ final Response response = RestAssured.get("http://localhost:8080/foos/1");
+ assertEquals(503, response.getStatusCode());
+ }
+
+ @Test
+ public void whenSendRequestWithoutCustomErrorFilter_thenError() {
+ final Response response = RestAssured.get("http://localhost:8080/foos/1");
+ assertEquals(500, response.getStatusCode());
+ }
+
+}
diff --git a/spring-security-modules/spring-security-web-login/README.md b/spring-security-modules/spring-security-web-login/README.md
index 9521a430c2..8b9c1583f6 100644
--- a/spring-security-modules/spring-security-web-login/README.md
+++ b/spring-security-modules/spring-security-web-login/README.md
@@ -1,6 +1,6 @@
## Spring Security Login
-This module contains articles about login mechanisms with Spring Security
+This module contains articles about login mechanisms with Spring Security.
### The Course
The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
@@ -17,3 +17,12 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
```
mvn clean install
```
+
+### Run the Project
+
+- Run the application using Maven Cargo plugin.
+```
+mvn cargo:run
+```
+- Go to the login page at http://localhost:8082/spring-security-web-login/login.html
+- Login using ```user1/user1Pass``` details.
\ No newline at end of file
diff --git a/spring-security-modules/spring-security-web-login/pom.xml b/spring-security-modules/spring-security-web-login/pom.xml
index ac5393c1a0..3d9947c519 100644
--- a/spring-security-modules/spring-security-web-login/pom.xml
+++ b/spring-security-modules/spring-security-web-login/pom.xml
@@ -137,17 +137,9 @@
org.codehaus.cargo
- cargo-maven2-plugin
- ${cargo-maven2-plugin.version}
+ cargo-maven3-plugin
+ ${cargo-maven3-plugin.version}
- true
-
- jetty8x
- embedded
-
-
-
-
8082
@@ -160,7 +152,7 @@
- 1.6.1
+ 1.9.9
\ No newline at end of file
diff --git a/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/AppInitializer.java b/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/AppInitializer.java
index 4f38d190eb..cbdf8dc684 100644
--- a/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/AppInitializer.java
+++ b/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/AppInitializer.java
@@ -1,9 +1,5 @@
package com.baeldung;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRegistration;
-
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
@@ -11,10 +7,13 @@ import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.DispatcherServlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRegistration;
+
public class AppInitializer implements WebApplicationInitializer {
@Override
- public void onStartup(final ServletContext sc) throws ServletException {
+ public void onStartup(final ServletContext sc) {
AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
@@ -24,7 +23,7 @@ public class AppInitializer implements WebApplicationInitializer {
ServletRegistration.Dynamic appServlet = sc.addServlet("mvc", new DispatcherServlet(new GenericWebApplicationContext()));
appServlet.setLoadOnStartup(1);
appServlet.addMapping("/");
-
+
sc.addFilter("securityFilter", new DelegatingFilterProxy("springSecurityFilterChain"))
.addMappingForUrlPatterns(null, false, "/*");
diff --git a/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/security/CustomAccessDeniedHandler.java b/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/security/CustomAccessDeniedHandler.java
index 9d9fa81dc0..39355202e3 100644
--- a/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/security/CustomAccessDeniedHandler.java
+++ b/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/security/CustomAccessDeniedHandler.java
@@ -1,25 +1,22 @@
package com.baeldung.security;
-import java.io.IOException;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.access.AccessDeniedHandler;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
public static final Logger LOG = LoggerFactory.getLogger(CustomAccessDeniedHandler.class);
@Override
- public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exc) throws IOException, ServletException {
+ public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exc) throws IOException {
Authentication auth = SecurityContextHolder.getContext()
.getAuthentication();
if (auth != null) {
diff --git a/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/security/CustomAuthenticationFailureHandler.java b/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/security/CustomAuthenticationFailureHandler.java
index 410d3f1ce9..ce3f299dac 100644
--- a/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/security/CustomAuthenticationFailureHandler.java
+++ b/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/security/CustomAuthenticationFailureHandler.java
@@ -13,7 +13,7 @@ import java.util.Calendar;
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
- public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
+ public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException {
httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
String jsonPayload = "{\"message\" : \"%s\", \"timestamp\" : \"%s\" }";
diff --git a/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/security/CustomLogoutSuccessHandler.java b/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/security/CustomLogoutSuccessHandler.java
index 7949eee69a..ee3bd62958 100644
--- a/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/security/CustomLogoutSuccessHandler.java
+++ b/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/security/CustomLogoutSuccessHandler.java
@@ -12,12 +12,6 @@ import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuc
public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler implements LogoutSuccessHandler {
- public CustomLogoutSuccessHandler() {
- super();
- }
-
- // API
-
@Override
public void onLogoutSuccess(final HttpServletRequest request, final HttpServletResponse response, final Authentication authentication) throws IOException, ServletException {
final String refererUrl = request.getHeader("Referer");
diff --git a/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/security/config/SecSecurityConfig.java b/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/security/config/SecSecurityConfig.java
index 15fa06aa3e..cfdaf7a13e 100644
--- a/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/security/config/SecSecurityConfig.java
+++ b/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/security/config/SecSecurityConfig.java
@@ -23,10 +23,6 @@ import com.baeldung.security.CustomLogoutSuccessHandler;
@Profile("!https")
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {
- public SecSecurityConfig() {
- super();
- }
-
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
@@ -81,7 +77,7 @@ public class SecSecurityConfig extends WebSecurityConfigurerAdapter {
public AuthenticationFailureHandler authenticationFailureHandler() {
return new CustomAuthenticationFailureHandler();
}
-
+
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
diff --git a/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/spring/ChannelSecSecurityConfig.java b/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/spring/ChannelSecSecurityConfig.java
index e9a6a9e120..151df18d11 100644
--- a/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/spring/ChannelSecSecurityConfig.java
+++ b/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/spring/ChannelSecSecurityConfig.java
@@ -17,10 +17,6 @@ import com.baeldung.security.CustomLogoutSuccessHandler;
@Profile("https")
public class ChannelSecSecurityConfig extends WebSecurityConfigurerAdapter {
- public ChannelSecSecurityConfig() {
- super();
- }
-
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
diff --git a/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/spring/MvcConfig.java b/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/spring/MvcConfig.java
index 082477c98c..7b27d637be 100644
--- a/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/spring/MvcConfig.java
+++ b/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/spring/MvcConfig.java
@@ -13,12 +13,6 @@ import org.springframework.web.servlet.view.JstlView;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
- public MvcConfig() {
- super();
- }
-
- // API
-
@Override
public void addViewControllers(final ViewControllerRegistry registry) {
diff --git a/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/spring/RedirectionSecurityConfig.java b/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/spring/RedirectionSecurityConfig.java
index 3516438a6e..b27d999d56 100644
--- a/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/spring/RedirectionSecurityConfig.java
+++ b/spring-security-modules/spring-security-web-login/src/main/java/com/baeldung/spring/RedirectionSecurityConfig.java
@@ -11,10 +11,6 @@ import org.springframework.security.web.authentication.SavedRequestAwareAuthenti
//@Profile("!https")
public class RedirectionSecurityConfig extends WebSecurityConfigurerAdapter {
- public RedirectionSecurityConfig() {
- super();
- }
-
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
diff --git a/spring-web-modules/spring-rest-testing/README.md b/spring-web-modules/spring-rest-testing/README.md
index 2a77b5dded..806e67b7ec 100644
--- a/spring-web-modules/spring-rest-testing/README.md
+++ b/spring-web-modules/spring-rest-testing/README.md
@@ -11,7 +11,6 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
### Relevant Articles:
- [Integration Testing with the Maven Cargo plugin](https://www.baeldung.com/integration-testing-with-the-maven-cargo-plugin)
-- [Metrics for your Spring REST API](https://www.baeldung.com/spring-rest-api-metrics)
- [Testing Exceptions with Spring MockMvc](https://www.baeldung.com/spring-mvc-test-exceptions)
### Build the Project
diff --git a/spring-web-modules/spring-rest-testing/pom.xml b/spring-web-modules/spring-rest-testing/pom.xml
index 52c1f6418e..1390898bf9 100644
--- a/spring-web-modules/spring-rest-testing/pom.xml
+++ b/spring-web-modules/spring-rest-testing/pom.xml
@@ -21,19 +21,10 @@
org.springframework.boot
spring-boot-starter-web
-
- org.springframework.boot
- spring-boot-starter-actuator
-
org.aspectj
aspectjweaver
-
- org.apache.tomcat.embed
- tomcat-embed-jasper
- provided
-
org.springframework
@@ -69,14 +60,6 @@
org.springframework
spring-expression
-
- org.springframework
- spring-web
-
-
- org.springframework
- spring-webmvc
-
org.springframework.data
spring-data-commons
@@ -137,17 +120,6 @@
net.bytebuddy
byte-buddy
-
-
- javax.servlet
- javax.servlet-api
- provided
-
-
- javax.servlet
- jstl
- runtime
-
com.fasterxml.jackson.core
diff --git a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/spring/Application.java b/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/spring/Application.java
index c35c4d7e5e..78c9b88ddb 100644
--- a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/spring/Application.java
+++ b/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/spring/Application.java
@@ -1,38 +1,19 @@
package com.baeldung.spring;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.builder.SpringApplicationBuilder;
-import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
-import org.springframework.scheduling.annotation.EnableScheduling;
-import org.springframework.web.context.request.RequestContextListener;
/**
* Main Application Class - uses Spring Boot. Just run this as a normal Java
* class to run up a Jetty Server (on http://localhost:8082/spring-rest-full)
*
*/
-@EnableScheduling
@EnableAutoConfiguration
@ComponentScan("com.baeldung")
@SpringBootApplication
-public class Application extends SpringBootServletInitializer {
-
- @Override
- protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
- return application.sources(Application.class);
- }
-
- @Override
- public void onStartup(ServletContext sc) throws ServletException {
- // Manages the lifecycle of the root application context
- sc.addListener(new RequestContextListener());
- }
+public class Application {
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
diff --git a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/controller/RootController.java b/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/controller/RootController.java
deleted file mode 100644
index 005f6f023b..0000000000
--- a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/controller/RootController.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.baeldung.web.controller;
-
-import java.util.Map;
-
-import com.baeldung.web.metric.IActuatorMetricService;
-import com.baeldung.web.metric.IMetricService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-@Controller
-@RequestMapping(value = "/auth/")
-public class RootController {
-
- @Autowired
- private IMetricService metricService;
-
- @Autowired
- private IActuatorMetricService actMetricService;
-
- public RootController() {
- super();
- }
-
- // API
-
- @RequestMapping(value = "/metric", method = RequestMethod.GET)
- @ResponseBody
- public Map getMetric() {
- return metricService.getFullMetric();
- }
-
- @RequestMapping(value = "/status-metric", method = RequestMethod.GET)
- @ResponseBody
- public Map getStatusMetric() {
- return metricService.getStatusMetric();
- }
-
- @RequestMapping(value = "/metric-graph", method = RequestMethod.GET)
- @ResponseBody
- public Object[][] drawMetric() {
- final Object[][] result = metricService.getGraphData();
- for (int i = 1; i < result[0].length; i++) {
- result[0][i] = result[0][i].toString();
- }
- return result;
- }
-
-
-}
diff --git a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/IActuatorMetricService.java b/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/IActuatorMetricService.java
deleted file mode 100644
index 60bb43ee00..0000000000
--- a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/IActuatorMetricService.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.baeldung.web.metric;
-
-public interface IActuatorMetricService {
- Object[][] getGraphData();
-}
diff --git a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/ICustomActuatorMetricService.java b/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/ICustomActuatorMetricService.java
deleted file mode 100644
index 5126252e27..0000000000
--- a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/ICustomActuatorMetricService.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.baeldung.web.metric;
-
-public interface ICustomActuatorMetricService {
-
- void increaseCount(final int status);
-
- Object[][] getGraphData();
-}
diff --git a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/IMetricService.java b/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/IMetricService.java
deleted file mode 100644
index b8dfa60215..0000000000
--- a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/IMetricService.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.baeldung.web.metric;
-
-import java.util.Map;
-
-public interface IMetricService {
-
- void increaseCount(final String request, final int status);
-
- Map getFullMetric();
-
- Map getStatusMetric();
-
- Object[][] getGraphData();
-}
diff --git a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/MetricService.java b/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/MetricService.java
deleted file mode 100644
index fd3cccab3e..0000000000
--- a/spring-web-modules/spring-rest-testing/src/main/java/com/baeldung/web/metric/MetricService.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package com.baeldung.web.metric;
-
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import org.springframework.stereotype.Service;
-
-@Service
-public class MetricService implements IMetricService {
-
- private ConcurrentMap> metricMap;
- private ConcurrentMap statusMetric;
- private ConcurrentMap> timeMap;
- private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
-
- public MetricService() {
- super();
- metricMap = new ConcurrentHashMap>();
- statusMetric = new ConcurrentHashMap();
- timeMap = new ConcurrentHashMap>();
- }
-
- // API
-
- @Override
- public void increaseCount(final String request, final int status) {
- increaseMainMetric(request, status);
- increaseStatusMetric(status);
- updateTimeMap(status);
- }
-
- @Override
- public Map getFullMetric() {
- return metricMap;
- }
-
- @Override
- public Map getStatusMetric() {
- return statusMetric;
- }
-
- @Override
- public Object[][] getGraphData() {
- final int colCount = statusMetric.keySet().size() + 1;
- final Set allStatus = statusMetric.keySet();
- final int rowCount = timeMap.keySet().size() + 1;
-
- final Object[][] result = new Object[rowCount][colCount];
- result[0][0] = "Time";
-
- int j = 1;
- for (final int status : allStatus) {
- result[0][j] = status;
- j++;
- }
- int i = 1;
- ConcurrentMap tempMap;
- for (final Entry> entry : timeMap.entrySet()) {
- result[i][0] = entry.getKey();
- tempMap = entry.getValue();
- for (j = 1; j < colCount; j++) {
- result[i][j] = tempMap.get(result[0][j]);
- if (result[i][j] == null) {
- result[i][j] = 0;
- }
- }
- i++;
- }
-
- return result;
- }
-
- // NON-API
-
- private void increaseMainMetric(final String request, final int status) {
- ConcurrentHashMap statusMap = metricMap.get(request);
- if (statusMap == null) {
- statusMap = new ConcurrentHashMap();
- }
-
- Integer count = statusMap.get(status);
- if (count == null) {
- count = 1;
- } else {
- count++;
- }
- statusMap.put(status, count);
- metricMap.put(request, statusMap);
- }
-
- private void increaseStatusMetric(final int status) {
- final Integer statusCount = statusMetric.get(status);
- if (statusCount == null) {
- statusMetric.put(status, 1);
- } else {
- statusMetric.put(status, statusCount + 1);
- }
- }
-
- private void updateTimeMap(final int status) {
- final String time = dateFormat.format(new Date());
- ConcurrentHashMap statusMap = timeMap.get(time);
- if (statusMap == null) {
- statusMap = new ConcurrentHashMap();
- }
-
- Integer count = statusMap.get(status);
- if (count == null) {
- count = 1;
- } else {
- count++;
- }
- statusMap.put(status, count);
- timeMap.put(time, statusMap);
- }
-
-}
diff --git a/spring-web-modules/spring-rest-testing/src/main/resources/application.properties b/spring-web-modules/spring-rest-testing/src/main/resources/application.properties
index 52d93b4cff..cb9d72e41f 100644
--- a/spring-web-modules/spring-rest-testing/src/main/resources/application.properties
+++ b/spring-web-modules/spring-rest-testing/src/main/resources/application.properties
@@ -1,3 +1,2 @@
server.port=8082
server.servlet.context-path=/spring-rest-full
-endpoints.metrics.enabled=true
\ No newline at end of file
diff --git a/testing-modules/junit-5-advanced/README.md b/testing-modules/junit-5-advanced/README.md
index 7790cb6770..e970ba8c96 100644
--- a/testing-modules/junit-5-advanced/README.md
+++ b/testing-modules/junit-5-advanced/README.md
@@ -1,5 +1,6 @@
## Relevant Articles:
+- [Get the Name of the Currently Executing Test in JUnit](https://www.baeldung.com/junit-get-name-of-currently-executing-test)
- [JUnit 5 TestWatcher API](https://www.baeldung.com/junit-testwatcher)
- [JUnit Custom Display Name Generator API](https://www.baeldung.com/junit-custom-display-name-generator)
- [@TestInstance Annotation in JUnit 5](https://www.baeldung.com/junit-testinstance-annotation)
diff --git a/testing-modules/testng_command_line/README.md b/testing-modules/testng_command_line/README.md
index 881477f036..74cdafdbc6 100644
--- a/testing-modules/testng_command_line/README.md
+++ b/testing-modules/testng_command_line/README.md
@@ -1 +1,3 @@
### Relevant articles
+
+- [Running a TestNG Project From the Command Line](https://www.baeldung.com/testng-run-command-line)