diff --git a/aws-lambda/README.md b/aws-lambda/README.md
index 759c9dd506..0ae188fc97 100644
--- a/aws-lambda/README.md
+++ b/aws-lambda/README.md
@@ -6,3 +6,4 @@ This module contains articles about AWS Lambda
- [Using AWS Lambda with API Gateway](https://www.baeldung.com/aws-lambda-api-gateway)
- [Introduction to AWS Serverless Application Model](https://www.baeldung.com/aws-serverless)
- [How to Implement Hibernate in an AWS Lambda Function in Java](https://www.baeldung.com/java-aws-lambda-hibernate)
+- [Writing an Enterprise-Grade AWS Lambda in Java](https://www.baeldung.com/java-enterprise-aws-lambda)
diff --git a/core-java-modules/core-java-9/src/main/java/com/baeldung/java9/interfaces/CustomFoo.java b/core-java-modules/core-java-9/src/main/java/com/baeldung/java9/interfaces/CustomFoo.java
new file mode 100644
index 0000000000..388927fbfe
--- /dev/null
+++ b/core-java-modules/core-java-9/src/main/java/com/baeldung/java9/interfaces/CustomFoo.java
@@ -0,0 +1,10 @@
+package com.baeldung.java9.interfaces;
+
+public class CustomFoo implements Foo {
+
+ public static void main(String... args) {
+ Foo customFoo = new CustomFoo();
+ customFoo.bar(); // 'Hello world!'
+ Foo.buzz(); // 'Hello static world!'
+ }
+}
diff --git a/core-java-modules/core-java-9/src/main/java/com/baeldung/java9/interfaces/Foo.java b/core-java-modules/core-java-9/src/main/java/com/baeldung/java9/interfaces/Foo.java
new file mode 100644
index 0000000000..8ccee83b7e
--- /dev/null
+++ b/core-java-modules/core-java-9/src/main/java/com/baeldung/java9/interfaces/Foo.java
@@ -0,0 +1,22 @@
+package com.baeldung.java9.interfaces;
+
+public interface Foo {
+
+ public default void bar() {
+ System.out.print("Hello");
+ baz();
+ }
+
+ public static void buzz() {
+ System.out.print("Hello");
+ staticBaz();
+ }
+
+ private void baz() {
+ System.out.print(" world!");
+ }
+
+ private static void staticBaz() {
+ System.out.print(" static world!");
+ }
+}
diff --git a/core-java-modules/core-java-9/src/test/java/com/baeldung/java9/interfaces/CustomFooUnitTest.java b/core-java-modules/core-java-9/src/test/java/com/baeldung/java9/interfaces/CustomFooUnitTest.java
new file mode 100644
index 0000000000..d107c091fb
--- /dev/null
+++ b/core-java-modules/core-java-9/src/test/java/com/baeldung/java9/interfaces/CustomFooUnitTest.java
@@ -0,0 +1,38 @@
+package com.baeldung.java9.interfaces;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class CustomFooUnitTest {
+ private ByteArrayOutputStream outContent = new ByteArrayOutputStream();
+ private PrintStream originalOut = System.out;
+
+ @BeforeEach
+ void setup() {
+ System.setOut(new PrintStream(outContent));
+ }
+
+ @AfterEach
+ void tearDown() {
+ System.setOut(originalOut);
+ }
+
+ @Test
+ void givenACustomFooObject_whenCallingDefaultMethodBar_thenExpectedStringIsWrittenToSystemOut() {
+ CustomFoo customFoo = new CustomFoo();
+ customFoo.bar();
+ assertThat(outContent.toString()).isEqualTo("Hello world!");
+ }
+
+ @Test
+ void givenAFooInterface_whenCallingStaticMethodBuzz_thenExpectedStringIsWrittenToSystemOut() {
+ Foo.buzz();
+ assertThat(outContent.toString()).isEqualTo("Hello static world!");
+ }
+}
\ No newline at end of file
diff --git a/core-java-modules/core-java-arrays-guides/README.md b/core-java-modules/core-java-arrays-guides/README.md
index 7338ff9523..00bb6b53c8 100644
--- a/core-java-modules/core-java-arrays-guides/README.md
+++ b/core-java-modules/core-java-arrays-guides/README.md
@@ -8,3 +8,4 @@ This module contains complete guides about arrays in Java
- [What is \[Ljava.lang.Object;?](https://www.baeldung.com/java-tostring-array)
- [Guide to ArrayStoreException](https://www.baeldung.com/java-arraystoreexception)
- [Creating a Generic Array in Java](https://www.baeldung.com/java-generic-array)
+- [Maximum Size of Java Arrays](https://www.baeldung.com/java-arrays-max-size)
diff --git a/core-java-modules/core-java-exceptions-3/README.md b/core-java-modules/core-java-exceptions-3/README.md
index e1372381a8..f79eb41a8b 100644
--- a/core-java-modules/core-java-exceptions-3/README.md
+++ b/core-java-modules/core-java-exceptions-3/README.md
@@ -8,3 +8,4 @@
- [Localizing Exception Messages in Java](https://www.baeldung.com/java-localize-exception-messages)
- [Explanation of ClassCastException in Java](https://www.baeldung.com/java-classcastexception)
- [NoSuchFieldError in Java](https://www.baeldung.com/java-nosuchfielderror)
+- [IllegalAccessError in Java](https://www.baeldung.com/java-illegalaccesserror)
diff --git a/core-java-modules/core-java-networking-3/README.md b/core-java-modules/core-java-networking-3/README.md
index 09470fe88c..730231525f 100644
--- a/core-java-modules/core-java-networking-3/README.md
+++ b/core-java-modules/core-java-networking-3/README.md
@@ -5,4 +5,5 @@ This module contains articles about networking in Java
### Relevant Articles
- [Finding a Free Port in Java](https://www.baeldung.com/java-free-port)
+- [Downloading Email Attachments in Java](https://www.baeldung.com/java-download-email-attachments)
- [[<-- Prev]](/core-java-modules/core-java-networking-2)
diff --git a/core-java-modules/core-java-reflection-2/README.md b/core-java-modules/core-java-reflection-2/README.md
index 3195cddc42..4c888bdf58 100644
--- a/core-java-modules/core-java-reflection-2/README.md
+++ b/core-java-modules/core-java-reflection-2/README.md
@@ -5,3 +5,4 @@
- [Checking If a Method is Static Using Reflection in Java](https://www.baeldung.com/java-check-method-is-static)
- [Checking if a Java Class is ‘abstract’ Using Reflection](https://www.baeldung.com/java-reflection-is-class-abstract)
- [Invoking a Private Method in Java](https://www.baeldung.com/java-call-private-method)
+- [Finding All Classes in a Java Package](https://www.baeldung.com/java-find-all-classes-in-package)
diff --git a/core-java-modules/core-java-regex/README.md b/core-java-modules/core-java-regex/README.md
index 92321fa656..4c78f64d75 100644
--- a/core-java-modules/core-java-regex/README.md
+++ b/core-java-modules/core-java-regex/README.md
@@ -13,3 +13,5 @@
- [Regular Expressions \s and \s+ in Java](https://www.baeldung.com/java-regex-s-splus)
- [Validate Phone Numbers With Java Regex](https://www.baeldung.com/java-regex-validate-phone-numbers)
- [How to Count the Number of Matches for a Regex?](https://www.baeldung.com/java-count-regex-matches)
+- [Find All Numbers in a String in Java](https://www.baeldung.com/java-find-numbers-in-string)
+- [Understanding the Pattern.quote Method](https://www.baeldung.com/java-pattern-quote)
diff --git a/core-java-modules/core-java-regex/src/test/java/com/baeldung/ignore/pattern/metacharacters/IgnoringPatternMetacharactersUnitTest.java b/core-java-modules/core-java-regex/src/test/java/com/baeldung/ignore/pattern/metacharacters/IgnoringPatternMetacharactersUnitTest.java
index 921876c0d5..8c07282716 100644
--- a/core-java-modules/core-java-regex/src/test/java/com/baeldung/ignore/pattern/metacharacters/IgnoringPatternMetacharactersUnitTest.java
+++ b/core-java-modules/core-java-regex/src/test/java/com/baeldung/ignore/pattern/metacharacters/IgnoringPatternMetacharactersUnitTest.java
@@ -12,7 +12,7 @@ public class IgnoringPatternMetacharactersUnitTest {
private static final String patternStr = "$100.50";
@Test
- public void givenPatternStringHasMetacharacters_whenPatternMatchedWithoutEscapingMetacharacters_thenNoMatchesFound() {
+ public void whenMetacharactersNotEscaped_thenNoMatchesFound() {
Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(dollarAmounts);
@@ -25,7 +25,7 @@ public class IgnoringPatternMetacharactersUnitTest {
}
@Test
- public void givenPatternStringHasMetacharacters_whenPatternCompiledUsingManuallyMetaEscapedPattern_thenMatchingSuccessful() {
+ public void whenMetacharactersManuallyEscaped_thenMatchingSuccessful() {
String metaEscapedPatternStr = "\\Q" + patternStr + "\\E";
Pattern pattern = Pattern.compile(metaEscapedPatternStr);
Matcher matcher = pattern.matcher(dollarAmounts);
@@ -39,7 +39,7 @@ public class IgnoringPatternMetacharactersUnitTest {
}
@Test
- public void givenPatternStringHasMetacharacters_whenPatternCompiledUsingLiteralPatternFromQuote_thenMatchingSuccessful() {
+ public void whenMetacharactersEscapedUsingPatternQuote_thenMatchingSuccessful() {
String literalPatternStr = Pattern.quote(patternStr);
Pattern pattern = Pattern.compile(literalPatternStr);
Matcher matcher = pattern.matcher(dollarAmounts);
diff --git a/core-java-modules/core-java-security-3/README.md b/core-java-modules/core-java-security-3/README.md
index 4585b6cc86..970faaac88 100644
--- a/core-java-modules/core-java-security-3/README.md
+++ b/core-java-modules/core-java-security-3/README.md
@@ -4,5 +4,5 @@ This module contains articles about core Java Security
### Relevant Articles:
-- [Secret Key and String Conversion in Java](https://www.baeldung.com/secret-key-and-string-conversion-in-java/)
+- [Secret Key and String Conversion in Java](https://www.baeldung.com/java-secret-key-to-string)
- More articles: [[<-- prev]](/core-java-modules/core-java-security-2)
diff --git a/gradle/gradle-cucumber/README.md b/gradle/gradle-cucumber/README.md
new file mode 100644
index 0000000000..a92593e959
--- /dev/null
+++ b/gradle/gradle-cucumber/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles:
+
+- [Using Cucumber with Gradle](https://www.baeldung.com/java-cucumber-gradle)
diff --git a/gradle/gradle-jacoco/build.gradle b/gradle/gradle-jacoco/build.gradle
new file mode 100644
index 0000000000..ef9e0a9c7c
--- /dev/null
+++ b/gradle/gradle-jacoco/build.gradle
@@ -0,0 +1,54 @@
+
+plugins {
+ id 'java'
+ id 'jacoco'
+}
+
+ext {
+ junitVersion = '5.7.2'
+ lombokVersion = '1.18.20'
+}
+
+group 'com.com.baeldung'
+version '1.0-SNAPSHOT'
+
+repositories {
+ mavenCentral()
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+}
+
+dependencies {
+ testImplementation "org.junit.jupiter:junit-jupiter-api:${junitVersion}"
+ testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junitVersion}"
+
+ compileOnly "org.projectlombok:lombok:${lombokVersion}"
+ annotationProcessor "org.projectlombok:lombok:${lombokVersion}"
+}
+
+test {
+ useJUnitPlatform()
+
+ finalizedBy jacocoTestReport // report is always generated after tests run
+}
+
+jacocoTestReport {
+ dependsOn test // tests are required to run before generating the report
+
+ afterEvaluate {
+ classDirectories.setFrom(files(classDirectories.files.collect {
+ fileTree(dir: it, exclude: [
+ "com/baeldung/**/ExcludedPOJO.class",
+ "com/baeldung/**/*DTO.*",
+ "**/config/*"
+ ])
+ }))
+ }
+}
+
+jacoco {
+ toolVersion = "0.8.6"
+}
diff --git a/gradle/gradle-jacoco/gradle/wrapper/gradle-wrapper.jar b/gradle/gradle-jacoco/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000..e708b1c023
Binary files /dev/null and b/gradle/gradle-jacoco/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/gradle-jacoco/gradle/wrapper/gradle-wrapper.properties b/gradle/gradle-jacoco/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000..da9702f9e7
--- /dev/null
+++ b/gradle/gradle-jacoco/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradle/gradle-jacoco/gradlew b/gradle/gradle-jacoco/gradlew
new file mode 100755
index 0000000000..4f906e0c81
--- /dev/null
+++ b/gradle/gradle-jacoco/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradle/gradle-jacoco/gradlew.bat b/gradle/gradle-jacoco/gradlew.bat
new file mode 100644
index 0000000000..ac1b06f938
--- /dev/null
+++ b/gradle/gradle-jacoco/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/gradle/gradle-jacoco/lombok.config b/gradle/gradle-jacoco/lombok.config
new file mode 100644
index 0000000000..7a21e88040
--- /dev/null
+++ b/gradle/gradle-jacoco/lombok.config
@@ -0,0 +1 @@
+lombok.addLombokGeneratedAnnotation = true
diff --git a/gradle/gradle-jacoco/settings.gradle b/gradle/gradle-jacoco/settings.gradle
new file mode 100644
index 0000000000..b0ed8f1486
--- /dev/null
+++ b/gradle/gradle-jacoco/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'gradle-jacoco'
diff --git a/gradle/gradle-jacoco/src/main/java/com/baeldung/config/AppConfig.java b/gradle/gradle-jacoco/src/main/java/com/baeldung/config/AppConfig.java
new file mode 100644
index 0000000000..d103f4b4f5
--- /dev/null
+++ b/gradle/gradle-jacoco/src/main/java/com/baeldung/config/AppConfig.java
@@ -0,0 +1,11 @@
+package com.baeldung.config;
+
+import com.baeldung.service.ProductService;
+
+public class AppConfig {
+
+ public ProductService productService() {
+ return new ProductService();
+ }
+
+}
diff --git a/gradle/gradle-jacoco/src/main/java/com/baeldung/domain/Product.java b/gradle/gradle-jacoco/src/main/java/com/baeldung/domain/Product.java
new file mode 100644
index 0000000000..c64b6d2eae
--- /dev/null
+++ b/gradle/gradle-jacoco/src/main/java/com/baeldung/domain/Product.java
@@ -0,0 +1,12 @@
+package com.baeldung.domain;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Builder
+@Data
+public class Product {
+ private int id;
+ private String name;
+
+}
diff --git a/gradle/gradle-jacoco/src/main/java/com/baeldung/dto/ExcludedPOJO.java b/gradle/gradle-jacoco/src/main/java/com/baeldung/dto/ExcludedPOJO.java
new file mode 100644
index 0000000000..0f7278459e
--- /dev/null
+++ b/gradle/gradle-jacoco/src/main/java/com/baeldung/dto/ExcludedPOJO.java
@@ -0,0 +1,4 @@
+package com.baeldung.dto;
+
+public class ExcludedPOJO {
+}
diff --git a/gradle/gradle-jacoco/src/main/java/com/baeldung/dto/ProductDTO.java b/gradle/gradle-jacoco/src/main/java/com/baeldung/dto/ProductDTO.java
new file mode 100644
index 0000000000..0ae1659c14
--- /dev/null
+++ b/gradle/gradle-jacoco/src/main/java/com/baeldung/dto/ProductDTO.java
@@ -0,0 +1,4 @@
+package com.baeldung.dto;
+
+public class ProductDTO {
+}
diff --git a/gradle/gradle-jacoco/src/main/java/com/baeldung/generated/Customer.java b/gradle/gradle-jacoco/src/main/java/com/baeldung/generated/Customer.java
new file mode 100644
index 0000000000..e7bb837a5c
--- /dev/null
+++ b/gradle/gradle-jacoco/src/main/java/com/baeldung/generated/Customer.java
@@ -0,0 +1,11 @@
+package com.baeldung.generated;
+
+@Generated
+public class Customer {
+ // everything in this class will be excluded from jacoco report because of @Generated
+
+ @Override
+ public String toString() {
+ return "Customer{}";
+ }
+}
diff --git a/gradle/gradle-jacoco/src/main/java/com/baeldung/generated/Generated.java b/gradle/gradle-jacoco/src/main/java/com/baeldung/generated/Generated.java
new file mode 100644
index 0000000000..865df8ca8a
--- /dev/null
+++ b/gradle/gradle-jacoco/src/main/java/com/baeldung/generated/Generated.java
@@ -0,0 +1,15 @@
+package com.baeldung.generated;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Documented
+@Retention(RUNTIME)
+@Target({TYPE, METHOD})
+public @interface Generated {
+}
\ No newline at end of file
diff --git a/gradle/gradle-jacoco/src/main/java/com/baeldung/service/CustomerService.java b/gradle/gradle-jacoco/src/main/java/com/baeldung/service/CustomerService.java
new file mode 100644
index 0000000000..e6dbe8df5e
--- /dev/null
+++ b/gradle/gradle-jacoco/src/main/java/com/baeldung/service/CustomerService.java
@@ -0,0 +1,16 @@
+package com.baeldung.service;
+
+import com.baeldung.generated.Generated;
+
+public class CustomerService {
+
+ //this method will be excluded from coverage due to @Generated.
+ @Generated
+ public String getProductId() {
+ return "An ID";
+ }
+
+ public String getCustomerName() {
+ return "some name";
+ }
+}
diff --git a/gradle/gradle-jacoco/src/main/java/com/baeldung/service/ProductService.java b/gradle/gradle-jacoco/src/main/java/com/baeldung/service/ProductService.java
new file mode 100644
index 0000000000..5f73ddc7fd
--- /dev/null
+++ b/gradle/gradle-jacoco/src/main/java/com/baeldung/service/ProductService.java
@@ -0,0 +1,9 @@
+package com.baeldung.service;
+
+public class ProductService {
+ private static final double DISCOUNT = 0.25;
+
+ public double getSalePrice(double originalPrice) {
+ return originalPrice - originalPrice * DISCOUNT;
+ }
+}
diff --git a/gradle/gradle-jacoco/src/test/java/com/baeldung/service/CustomerServiceUnitTest.java b/gradle/gradle-jacoco/src/test/java/com/baeldung/service/CustomerServiceUnitTest.java
new file mode 100644
index 0000000000..63dd2c755a
--- /dev/null
+++ b/gradle/gradle-jacoco/src/test/java/com/baeldung/service/CustomerServiceUnitTest.java
@@ -0,0 +1,14 @@
+package com.baeldung.service;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+class CustomerServiceUnitTest {
+
+ @Test
+ public void givenCustomer_whenGetCustomer_thenReturnNewCustomer() {
+ CustomerService customerService = new CustomerService();
+ assertNotNull(customerService.getCustomerName());
+ }
+}
diff --git a/gradle/gradle-jacoco/src/test/java/com/baeldung/service/ProductServiceUnitTest.java b/gradle/gradle-jacoco/src/test/java/com/baeldung/service/ProductServiceUnitTest.java
new file mode 100644
index 0000000000..a9d216785a
--- /dev/null
+++ b/gradle/gradle-jacoco/src/test/java/com/baeldung/service/ProductServiceUnitTest.java
@@ -0,0 +1,15 @@
+package com.baeldung.service;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class ProductServiceUnitTest {
+
+ @Test
+ public void givenOriginalPrice_whenGetSalePrice_thenReturnsDiscountedPrice() {
+ ProductService productService = new ProductService();
+ double salePrice = productService.getSalePrice(100);
+ assertEquals(salePrice, 75);
+ }
+}
diff --git a/gradle/gradle-jacoco/src/test/resources/features/account_credited.feature b/gradle/gradle-jacoco/src/test/resources/features/account_credited.feature
new file mode 100644
index 0000000000..bd7940d1a5
--- /dev/null
+++ b/gradle/gradle-jacoco/src/test/resources/features/account_credited.feature
@@ -0,0 +1,6 @@
+Feature: Account is credited with amount
+
+ Scenario: Credit amount
+ Given account balance is 0.0
+ When the account is credited with 10.0
+ Then account should have a balance of 10.0
diff --git a/java-collections-conversions-2/pom.xml b/java-collections-conversions-2/pom.xml
index 7845e0d934..74f955ebdd 100644
--- a/java-collections-conversions-2/pom.xml
+++ b/java-collections-conversions-2/pom.xml
@@ -44,6 +44,12 @@
${hamcrest.version}
test
+
+ io.vavr
+ vavr
+ 0.10.3
+
+
diff --git a/java-collections-conversions-2/src/test/java/com/baeldung/setiteration/SetIteration.java b/java-collections-conversions-2/src/test/java/com/baeldung/setiteration/SetIteration.java
new file mode 100644
index 0000000000..ee0943ec1c
--- /dev/null
+++ b/java-collections-conversions-2/src/test/java/com/baeldung/setiteration/SetIteration.java
@@ -0,0 +1,74 @@
+package com.baeldung.setiteration;
+
+import com.google.common.collect.Sets;
+import io.vavr.collection.Stream;
+import org.junit.jupiter.api.Test;
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+class SetIteration {
+
+ @Test
+ void givenSet_whenIteratorUsed_shouldIterateOverElements() {
+ // given
+ Set names = Sets.newHashSet("Tom", "Jane", "Karen");
+
+ // when
+ Iterator namesIterator1 = names.iterator();
+ Iterator namesIterator2 = names.iterator();
+
+ // then
+ namesIterator1.forEachRemaining(System.out::println);
+ while(namesIterator2.hasNext()) {
+ System.out.println(namesIterator2.next());
+ }
+ }
+
+ @Test
+ void givenSet_whenStreamUsed_shouldIterateOverElements() {
+ // given
+ Set names = Sets.newHashSet("Tom", "Jane", "Karen");
+
+ // when & then
+ String namesJoined = names.stream()
+ .map(String::toUpperCase)
+ .peek(System.out::println)
+ .collect(Collectors.joining());
+ }
+
+ @Test
+ void givenSet_whenEnhancedLoopUsed_shouldIterateOverElements() {
+ // given
+ Set names = Sets.newHashSet("Tom", "Jane", "Karen");
+
+ // when & then
+ for (String name : names) {
+ System.out.println(name);
+ }
+ }
+
+ @Test
+ void givenSet_whenMappedToArray_shouldIterateOverElements() {
+ // given
+ Set names = Sets.newHashSet("Tom", "Jane", "Karen");
+
+ // when & then
+ Object[] namesArray = names.toArray();
+ for (int i = 0; i < namesArray.length; i++) {
+ System.out.println(i + ": " + namesArray[i]);
+ }
+ }
+
+ @Test
+ void givenSet_whenZippedWithIndex_shouldIterateOverElements() {
+ // given
+ Set names = Sets.newHashSet("Tom", "Jane", "Karen");
+
+ // when & then
+ Stream.ofAll(names)
+ .zipWithIndex()
+ .forEach(t -> System.out.println(t._2() + ": " + t._1()));
+ }
+}
diff --git a/kubernetes/k8s-intro/README.md b/kubernetes/k8s-intro/README.md
index 6ac593452c..8c11f4d53e 100644
--- a/kubernetes/k8s-intro/README.md
+++ b/kubernetes/k8s-intro/README.md
@@ -17,3 +17,4 @@ If you get a valid response, then you're good to go.
- [Paging and Async Calls with the Kubernetes API](https://www.baeldung.com/java-kubernetes-paging-async)
- [Using Watch with the Kubernetes API](https://www.baeldung.com/java-kubernetes-watch)
- [Using Namespaces and Selectors With the Kubernetes Java API](https://www.baeldung.com/java-kubernetes-namespaces-selectors)
+- [Creating, Updating and Deleting Resources with the Java Kubernetes API](https://www.baeldung.com/java-kubernetes-api-crud)
diff --git a/libraries-data-3/README.md b/libraries-data-3/README.md
index fffdf65252..2c01d2e320 100644
--- a/libraries-data-3/README.md
+++ b/libraries-data-3/README.md
@@ -3,7 +3,7 @@
This module contains articles about libraries for data processing in Java.
### Relevant articles
-- [Kafka Streams vs Kafka Consumer]()
+- [Kafka Streams vs Kafka Consumer](https://www.baeldung.com/java-kafka-streams-vs-kafka-consumer)
- More articles: [[<-- prev]](/../libraries-data-2)
##### Building the project
diff --git a/logging-modules/log4j/README.md b/logging-modules/log4j/README.md
index a7a7ea9643..371d0246ce 100644
--- a/logging-modules/log4j/README.md
+++ b/logging-modules/log4j/README.md
@@ -3,3 +3,4 @@
- [Introduction to SLF4J](http://www.baeldung.com/slf4j-with-log4j2-logback)
- [A Guide to Rolling File Appenders](http://www.baeldung.com/java-logging-rolling-file-appenders)
- [Logging Exceptions Using SLF4J](https://www.baeldung.com/slf4j-log-exceptions)
+- [Log4j Warning: "No Appenders Could Be Found for Logger"](https://www.baeldung.com/log4j-no-appenders-found)
diff --git a/logging-modules/log4j/src/main/java/com/baeldung/log4j/NoAppenderExample.java b/logging-modules/log4j/src/main/java/com/baeldung/log4j/NoAppenderExample.java
new file mode 100644
index 0000000000..9bd8a06537
--- /dev/null
+++ b/logging-modules/log4j/src/main/java/com/baeldung/log4j/NoAppenderExample.java
@@ -0,0 +1,18 @@
+package com.baeldung.log4j;
+
+import org.apache.log4j.Logger;
+
+public class NoAppenderExample {
+
+ private final static Logger logger = Logger.getLogger(NoAppenderExample.class);
+
+ public static void main(String[] args) {
+
+ //Setup default appender
+ //BasicConfigurator.configure();
+
+ //Define path to configuration file
+ //PropertyConfigurator.configure("src\\main\\resources\\log4j.properties");
+ logger.info("Info log message");
+ }
+}
diff --git a/logging-modules/log4j/src/main/resources/log4j.properties b/logging-modules/log4j/src/main/resources/log4j.properties
new file mode 100644
index 0000000000..b10ba2b7d4
--- /dev/null
+++ b/logging-modules/log4j/src/main/resources/log4j.properties
@@ -0,0 +1,5 @@
+log4j.rootLogger=INFO, stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n
\ No newline at end of file
diff --git a/logging-modules/log4j/src/main/resources/log4j.xml b/logging-modules/log4j/src/main/resources/log4j.xml
index 562d6920f9..3004649edf 100644
--- a/logging-modules/log4j/src/main/resources/log4j.xml
+++ b/logging-modules/log4j/src/main/resources/log4j.xml
@@ -90,6 +90,8 @@
+
+
diff --git a/mapstruct/pom.xml b/mapstruct/pom.xml
index 1434db0d54..1e7ce6cbfc 100644
--- a/mapstruct/pom.xml
+++ b/mapstruct/pom.xml
@@ -34,7 +34,12 @@
org.projectlombok
lombok
- ${org.projectlombok.version}
+ ${lombok.version}
+
+
+ org.projectlombok
+ lombok-mapstruct-binding
+ ${lombok.mapstruct.binding.version}
org.assertj
@@ -63,7 +68,12 @@
org.projectlombok
lombok
- ${org.projectlombok.version}
+ ${lombok.version}
+
+
+ org.projectlombok
+ lombok-mapstruct-binding
+ ${lombok.mapstruct.binding.version}
@@ -72,11 +82,11 @@
- 1.3.1.Final
+ 1.4.2.Final
4.3.4.RELEASE
1.8
1.8
- 1.18.4
+ 0.2.0
3.16.1
diff --git a/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/insertnull/DBConfig.java b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/insertnull/DBConfig.java
new file mode 100644
index 0000000000..3907434239
--- /dev/null
+++ b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/insertnull/DBConfig.java
@@ -0,0 +1,26 @@
+package com.baeldung.insertnull;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+public class DBConfig {
+
+ private static Connection INSTANCE;
+
+ public static Connection getConnection() throws SQLException {
+ if (INSTANCE == null) {
+ INSTANCE = DriverManager.getConnection("jdbc:h2:mem:insertnull", "user", "password");
+ createPersonTable();
+ }
+ return INSTANCE;
+ }
+
+ private static void createPersonTable() throws SQLException {
+ try(Statement statement = INSTANCE.createStatement()) {
+ String sql = "CREATE TABLE Person (id INTEGER not null, name VARCHAR(50), lastName VARCHAR(50), age INTEGER, PRIMARY KEY (id))";
+ statement.executeUpdate(sql);
+ }
+ }
+}
diff --git a/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/insertnull/Person.java b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/insertnull/Person.java
new file mode 100644
index 0000000000..e261a7d74c
--- /dev/null
+++ b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/insertnull/Person.java
@@ -0,0 +1,48 @@
+package com.baeldung.insertnull;
+
+public class Person {
+
+ private Integer id;
+ private String name;
+ private String lastName;
+ private Integer age;
+
+ public Person(Integer id, String name, String lastName, Integer age) {
+ this.id = id;
+ this.name = name;
+ this.lastName = lastName;
+ this.age = age;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public Integer getAge() {
+ return age;
+ }
+
+ public void setAge(Integer age) {
+ this.age = age;
+ }
+}
diff --git a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/insertnull/InsertNullUnitTest.java b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/insertnull/InsertNullUnitTest.java
new file mode 100644
index 0000000000..508fa98e8f
--- /dev/null
+++ b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/insertnull/InsertNullUnitTest.java
@@ -0,0 +1,50 @@
+package com.baeldung.insertnull;
+
+import org.junit.jupiter.api.Test;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+public class InsertNullUnitTest {
+
+ private final String SQL = "INSERT INTO Person VALUES(?,?,?,?)";
+
+ @Test
+ public void givenNewPerson_whenSetNullIsUsed_thenNewRecordIsCreated() throws SQLException {
+ Person person = new Person(1, "John", "Doe", null);
+
+ try (PreparedStatement preparedStatement = DBConfig.getConnection().prepareStatement(SQL)) {
+ preparedStatement.setInt(1, person.getId());
+ preparedStatement.setString(2, person.getName());
+ preparedStatement.setString(3, person.getLastName());
+ if (person.getAge() == null) {
+ preparedStatement.setNull(4, Types.INTEGER);
+ }
+ else {
+ preparedStatement.setInt(4, person.getAge());
+ }
+ int noOfRows = preparedStatement.executeUpdate();
+
+ assertThat(noOfRows, equalTo(1));
+ }
+ }
+
+ @Test
+ public void givenNewPerson_whenSetObjectIsUsed_thenNewRecordIsCreated() throws SQLException {
+ Person person = new Person(2, "John", "Doe", null);
+
+ try (PreparedStatement preparedStatement = DBConfig.getConnection().prepareStatement(SQL)) {
+ preparedStatement.setInt(1, person.getId());
+ preparedStatement.setString(2, person.getName());
+ preparedStatement.setString(3, person.getLastName());
+ preparedStatement.setObject(4, person.getAge(), Types.INTEGER);
+ int noOfRows = preparedStatement.executeUpdate();
+
+ assertThat(noOfRows, equalTo(1));
+ }
+ }
+}
diff --git a/persistence-modules/java-jpa-3/README.md b/persistence-modules/java-jpa-3/README.md
index e607043880..c024d7c540 100644
--- a/persistence-modules/java-jpa-3/README.md
+++ b/persistence-modules/java-jpa-3/README.md
@@ -11,3 +11,5 @@ This module contains articles about the Java Persistence API (JPA) in Java.
- [A Guide to MultipleBagFetchException in Hibernate](https://www.baeldung.com/java-hibernate-multiplebagfetchexception)
- [How to Convert a Hibernate Proxy to a Real Entity Object](https://www.baeldung.com/hibernate-proxy-to-real-entity-object)
- [Returning an Auto-Generated Id with JPA](https://www.baeldung.com/jpa-get-auto-generated-id)
+- [How to Return Multiple Entities In JPA Query](https://www.baeldung.com/jpa-return-multiple-entities)
+- [Defining Unique Constraints in JPA](https://www.baeldung.com/jpa-unique-constraints)
diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/uniqueconstraints/Address.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/uniqueconstraints/Address.java
new file mode 100644
index 0000000000..b20de6a471
--- /dev/null
+++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/uniqueconstraints/Address.java
@@ -0,0 +1,37 @@
+package com.baeldung.jpa.uniqueconstraints;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table
+public class Address implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ private String streetAddress;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getStreetAddress() {
+ return streetAddress;
+ }
+
+ public void setStreetAddress(String streetAddress) {
+ this.streetAddress = streetAddress;
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/uniqueconstraints/Person.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/uniqueconstraints/Person.java
new file mode 100644
index 0000000000..c5df90df73
--- /dev/null
+++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/uniqueconstraints/Person.java
@@ -0,0 +1,116 @@
+package com.baeldung.jpa.uniqueconstraints;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+@Entity
+@Table(uniqueConstraints = { @UniqueConstraint(name = "UniqueNumberAndStatus", columnNames = { "personNumber", "isActive" }),
+ @UniqueConstraint(name = "UniqueSecurityAndDepartment", columnNames = { "securityNumber", "departmentCode" }),
+ @UniqueConstraint(name = "UniqueNumberAndAddress", columnNames = { "personNumber", "address" }) })
+public class Person implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ private String name;
+
+ private String password;
+
+ @Column(unique = true)
+ private String email;
+
+ @Column(unique = true)
+ private Long personNumber;
+
+ private Boolean isActive;
+
+ private String securityNumber;
+
+ private String departmentCode;
+
+ @Column(unique = true)
+ @JoinColumn(name = "addressId", referencedColumnName = "id")
+ private Address address;
+
+ 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 getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public Long getPersonNumber() {
+ return personNumber;
+ }
+
+ public void setPersonNumber(Long personNumber) {
+ this.personNumber = personNumber;
+ }
+
+ public Boolean getIsActive() {
+ return isActive;
+ }
+
+ public void setIsActive(Boolean isActive) {
+ this.isActive = isActive;
+ }
+
+ public String getScode() {
+ return securityNumber;
+ }
+
+ public void setScode(String scode) {
+ this.securityNumber = scode;
+ }
+
+ public String getDcode() {
+ return departmentCode;
+ }
+
+ public void setDcode(String dcode) {
+ this.departmentCode = dcode;
+ }
+
+ public Address getAddress() {
+ return address;
+ }
+
+ public void setAddress(Address address) {
+ this.address = address;
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml b/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml
index 666fc1500a..1166aaca71 100644
--- a/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml
+++ b/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml
@@ -113,6 +113,22 @@
+
+ org.hibernate.jpa.HibernatePersistenceProvider
+ com.baeldung.jpa.uniqueconstraints.Person
+ com.baeldung.jpa.uniqueconstraints.Address
+ true
+
+
+
+
+
+
+
+
+
+
+
org.hibernate.jpa.HibernatePersistenceProvider
com.baeldung.jpa.returnmultipleentities.Channel
diff --git a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/uniqueconstraints/UniqueColumnIntegrationTest.java b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/uniqueconstraints/UniqueColumnIntegrationTest.java
new file mode 100644
index 0000000000..ca776ba00b
--- /dev/null
+++ b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/uniqueconstraints/UniqueColumnIntegrationTest.java
@@ -0,0 +1,119 @@
+package com.baeldung.jpa.uniqueconstraints;
+
+import java.util.Optional;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+import org.hibernate.exception.ConstraintViolationException;
+import org.junit.Assert;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+public class UniqueColumnIntegrationTest {
+
+ private static EntityManagerFactory factory;
+ private static EntityManager entityManager;
+
+ @BeforeAll
+ public static void setup() {
+ factory = Persistence.createEntityManagerFactory("jpa-unique-constraints");
+ entityManager = factory.createEntityManager();
+ }
+
+ @Test
+ public void whenPersistPersonWithSameNumber_thenConstraintViolationException() {
+ Person person1 = new Person();
+ person1.setPersonNumber(2000L);
+ person1.setEmail("john.beth@gmail.com");
+
+ Person person2 = new Person();
+ person2.setPersonNumber(2000L);
+ person2.setEmail("anthony.green@gmail.com");
+
+ entityManager.getTransaction().begin();
+ entityManager.persist(person1);
+ entityManager.getTransaction().commit();
+
+ entityManager.getTransaction().begin();
+ try {
+ entityManager.persist(person2);
+ entityManager.getTransaction().commit();
+ Assert.fail("Should raise an exception - unique key violation");
+ } catch (Exception ex) {
+ Assert.assertTrue(Optional.of(ex)
+ .map(Throwable::getCause)
+ .map(Throwable::getCause)
+ .filter(x -> x instanceof ConstraintViolationException)
+ .isPresent());
+ } finally {
+ entityManager.getTransaction().rollback();
+ }
+ }
+
+ @Test
+ public void whenPersistPersonWithSameEmail_thenConstraintViolationException() {
+ Person person1 = new Person();
+ person1.setPersonNumber(4000L);
+ person1.setEmail("timm.beth@gmail.com");
+
+ Person person2 = new Person();
+ person2.setPersonNumber(3000L);
+ person2.setEmail("timm.beth@gmail.com");
+
+ entityManager.getTransaction().begin();
+ entityManager.persist(person1);
+ entityManager.getTransaction().commit();
+
+ entityManager.getTransaction().begin();
+ try {
+ entityManager.persist(person2);
+ entityManager.getTransaction().commit();
+ Assert.fail("Should raise an exception - unique key violation");
+ } catch (Exception ex) {
+ Assert.assertTrue(Optional.of(ex)
+ .map(Throwable::getCause)
+ .map(Throwable::getCause)
+ .filter(x -> x instanceof ConstraintViolationException)
+ .isPresent());
+ } finally {
+ entityManager.getTransaction().rollback();
+ }
+ }
+
+ @Test
+ public void whenPersistPersonWithSameAddress_thenConstraintViolationException() {
+ Person person1 = new Person();
+ person1.setPersonNumber(5000L);
+ person1.setEmail("chris.beck@gmail.com");
+
+ Address address1 = new Address();
+ address1.setStreetAddress("20 Street");
+ person1.setAddress(address1);
+
+ Person person2 = new Person();
+ person2.setPersonNumber(6000L);
+ person2.setEmail("mark.jonson@gmail.com");
+ person2.setAddress(address1);
+
+ entityManager.getTransaction().begin();
+ entityManager.persist(person1);
+ entityManager.getTransaction().commit();
+
+ entityManager.getTransaction().begin();
+ try {
+ entityManager.persist(person2);
+ entityManager.getTransaction().commit();
+ Assert.fail("Should raise an exception - unique key violation");
+ } catch (Exception ex) {
+ Assert.assertTrue(Optional.of(ex)
+ .map(Throwable::getCause)
+ .map(Throwable::getCause)
+ .filter(x -> x instanceof ConstraintViolationException)
+ .isPresent());
+ } finally {
+ entityManager.getTransaction().rollback();
+ }
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/uniqueconstraints/UniqueConstraintIntegrationTest.java b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/uniqueconstraints/UniqueConstraintIntegrationTest.java
new file mode 100644
index 0000000000..f12313724e
--- /dev/null
+++ b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/uniqueconstraints/UniqueConstraintIntegrationTest.java
@@ -0,0 +1,116 @@
+package com.baeldung.jpa.uniqueconstraints;
+
+import java.util.Optional;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+import org.hibernate.exception.ConstraintViolationException;
+import org.junit.Assert;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+public class UniqueConstraintIntegrationTest {
+ private static EntityManagerFactory factory;
+ private static EntityManager entityManager;
+
+ @BeforeAll
+ public static void setup() {
+ factory = Persistence.createEntityManagerFactory("jpa-unique-constraints");
+ entityManager = factory.createEntityManager();
+ }
+
+ @Test
+ public void whenPersistPersonWithSameNumberAndStatus_thenConstraintViolationException() {
+ Person person1 = new Person();
+ person1.setPersonNumber(12345L);
+ person1.setIsActive(Boolean.TRUE);
+
+ Person person2 = new Person();
+ person2.setPersonNumber(12345L);
+ person2.setIsActive(Boolean.TRUE);
+
+ entityManager.getTransaction().begin();
+ entityManager.persist(person1);
+ entityManager.getTransaction().commit();
+
+ entityManager.getTransaction().begin();
+ try {
+ entityManager.persist(person2);
+ entityManager.getTransaction().commit();
+ Assert.fail("Should raise an exception - unique key violation");
+ } catch (Exception ex) {
+ Assert.assertTrue(Optional.of(ex)
+ .map(Throwable::getCause)
+ .map(Throwable::getCause)
+ .filter(x -> x instanceof ConstraintViolationException)
+ .isPresent());
+ } finally {
+ entityManager.getTransaction().rollback();
+ }
+ }
+
+ @Test
+ public void whenPersistPersonWithSameSCodeAndDecode_thenConstraintViolationException() {
+ Person person1 = new Person();
+ person1.setDcode("Sec1");
+ person1.setScode("Axybg356");
+
+ Person person2 = new Person();
+ person2.setDcode("Sec1");
+ person2.setScode("Axybg356");
+
+ entityManager.getTransaction().begin();
+ entityManager.persist(person1);
+ entityManager.getTransaction().commit();
+
+ entityManager.getTransaction().begin();
+ try {
+ entityManager.persist(person2);
+ entityManager.getTransaction().commit();
+ Assert.fail("Should raise an exception - unique key violation");
+ } catch (Exception ex) {
+ Assert.assertTrue(Optional.of(ex)
+ .map(Throwable::getCause)
+ .map(Throwable::getCause)
+ .filter(x -> x instanceof ConstraintViolationException)
+ .isPresent());
+ } finally {
+ entityManager.getTransaction().rollback();
+ }
+ }
+
+ @Test
+ public void whenPersistPersonWithSameNumberAndAddress_thenConstraintViolationException() {
+ Address address1 = new Address();
+ address1.setStreetAddress("40 Street");
+
+ Person person1 = new Person();
+ person1.setPersonNumber(54321L);
+ person1.setAddress(address1);
+
+ Person person2 = new Person();
+ person2.setPersonNumber(99999L);
+ person2.setAddress(address1);
+
+ entityManager.getTransaction().begin();
+ entityManager.persist(person1);
+ entityManager.getTransaction().commit();
+
+ entityManager.getTransaction().begin();
+ try {
+ entityManager.persist(person2);
+ entityManager.getTransaction().commit();
+ Assert.fail("Should raise an exception - unique key violation");
+ } catch (Exception ex) {
+ Assert.assertTrue(Optional.of(ex)
+ .map(Throwable::getCause)
+ .map(Throwable::getCause)
+ .filter(x -> x instanceof ConstraintViolationException)
+ .isPresent());
+ } finally {
+ entityManager.getTransaction().rollback();
+ }
+ }
+}
\ No newline at end of file
diff --git a/reactor-core/README.md b/reactor-core/README.md
index 08dac354ab..21ccc1ed92 100644
--- a/reactor-core/README.md
+++ b/reactor-core/README.md
@@ -9,3 +9,4 @@ This module contains articles about Reactor Core.
- [Programmatically Creating Sequences with Project Reactor](https://www.baeldung.com/flux-sequences-reactor)
- [How to Extract a Mono’s Content in Java](https://www.baeldung.com/java-string-from-mono)
- [How to Convert Mono> Into Flux](https://www.baeldung.com/java-mono-list-to-flux)
+- [Project Reactor: map() vs flatMap()](https://www.baeldung.com/java-reactor-map-flatmap)
diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml
index 53af0de315..7a93cabb82 100644
--- a/spring-boot-modules/pom.xml
+++ b/spring-boot-modules/pom.xml
@@ -73,6 +73,7 @@
spring-boot-actuator
spring-boot-data-2
spring-boot-react
+ spring-boot-validation
diff --git a/spring-boot-modules/spring-boot-exceptions/README.md b/spring-boot-modules/spring-boot-exceptions/README.md
index 33ae193fb8..97a51203c7 100644
--- a/spring-boot-modules/spring-boot-exceptions/README.md
+++ b/spring-boot-modules/spring-boot-exceptions/README.md
@@ -5,3 +5,4 @@ This module contains articles about Spring Boot Exceptions
### Relevant Articles:
- [The BeanDefinitionOverrideException in Spring Boot](https://www.baeldung.com/spring-boot-bean-definition-override-exception)
+- [Spring Boot Error ApplicationContextException](https://www.baeldung.com/spring-boot-application-context-exception)
diff --git a/spring-boot-modules/spring-boot-exceptions/pom.xml b/spring-boot-modules/spring-boot-exceptions/pom.xml
index c0c335f55c..9866c418be 100644
--- a/spring-boot-modules/spring-boot-exceptions/pom.xml
+++ b/spring-boot-modules/spring-boot-exceptions/pom.xml
@@ -15,6 +15,14 @@
../
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
spring-boot-exceptions
diff --git a/spring-boot-modules/spring-boot-exceptions/src/test/java/com/baeldung/applicationcontextexception/MainEntryPoint.java b/spring-boot-modules/spring-boot-exceptions/src/test/java/com/baeldung/applicationcontextexception/MainEntryPoint.java
new file mode 100644
index 0000000000..c187399636
--- /dev/null
+++ b/spring-boot-modules/spring-boot-exceptions/src/test/java/com/baeldung/applicationcontextexception/MainEntryPoint.java
@@ -0,0 +1,14 @@
+package com.baeldung.applicationcontextexception;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+//Remove this annotation to produce ApplicationContextException error
+@SpringBootApplication
+public class MainEntryPoint {
+
+ public static void main(String[] args) {
+ SpringApplication.run(MainEntryPoint.class, args);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-keycloak/pom.xml b/spring-boot-modules/spring-boot-keycloak/pom.xml
index 37d57d6556..b80dbfa191 100644
--- a/spring-boot-modules/spring-boot-keycloak/pom.xml
+++ b/spring-boot-modules/spring-boot-keycloak/pom.xml
@@ -76,7 +76,7 @@
- 11.0.2
+ 13.0.1
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-testing/pom.xml b/spring-boot-modules/spring-boot-testing/pom.xml
index 1860818b7b..f4df242f2c 100644
--- a/spring-boot-modules/spring-boot-testing/pom.xml
+++ b/spring-boot-modules/spring-boot-testing/pom.xml
@@ -147,6 +147,7 @@
1.2-groovy-2.4
1.6
0.7.2
+ 2.5.0
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-validation/.gitignore b/spring-boot-modules/spring-boot-validation/.gitignore
new file mode 100644
index 0000000000..8f5ee06047
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validation/.gitignore
@@ -0,0 +1,63 @@
+# Created by https://www.gitignore.io/api/eclipse
+
+### Eclipse ###
+
+.metadata
+target/
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.settings/
+.loadpath
+.recommenders
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# PyDev specific (Python IDE for Eclipse)
+*.pydevproject
+
+# CDT-specific (C/C++ Development Tooling)
+.cproject
+
+# Java annotation processor (APT)
+.factorypath
+
+# PDT-specific (PHP Development Tools)
+.buildpath
+
+# sbteclipse plugin
+.target
+
+# Tern plugin
+.tern-project
+
+# TeXlipse plugin
+.texlipse
+
+# STS (Spring Tool Suite)
+.springBeans
+
+# Code Recommenders
+.recommenders/
+
+# Scala IDE specific (Scala & Java development for Eclipse)
+.cache-main
+.scala_dependencies
+.worksheet
+
+### Eclipse Patch ###
+# Eclipse Core
+.project
+
+# JDT-specific (Eclipse Java Development Tools)
+.classpath
+
+# End of https://www.gitignore.io/api/eclipse
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-validation/README.md b/spring-boot-modules/spring-boot-validation/README.md
new file mode 100644
index 0000000000..8c3c8b9305
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validation/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles
+
+- [Spring Validation in the Service Layer](https://www.baeldung.com/spring-service-layer-validation)
diff --git a/spring-boot-modules/spring-boot-validation/pom.xml b/spring-boot-modules/spring-boot-validation/pom.xml
new file mode 100644
index 0000000000..1aba8efeac
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validation/pom.xml
@@ -0,0 +1,41 @@
+
+
+
+ 4.0.0
+
+ com.baeldung
+ spring-boot-validation
+ 0.0.1-SNAPSHOT
+
+
+ com.baeldung
+ parent-boot-2
+ 0.0.1-SNAPSHOT
+ ../../parent-boot-2
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.hibernate.validator
+ hibernate-validator
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/SpringServiceLayerValidationApp.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/SpringServiceLayerValidationApp.java
new file mode 100644
index 0000000000..b976342dda
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/SpringServiceLayerValidationApp.java
@@ -0,0 +1,13 @@
+package com.baeldung.spring.servicevalidation;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SpringServiceLayerValidationApp {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SpringServiceLayerValidationApp.class, args);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/controller/UserAccountController.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/controller/UserAccountController.java
new file mode 100644
index 0000000000..33d9966e42
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/controller/UserAccountController.java
@@ -0,0 +1,22 @@
+package com.baeldung.spring.servicevalidation.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.spring.servicevalidation.domain.UserAccount;
+import com.baeldung.spring.servicevalidation.service.UserAccountService;
+
+@RestController
+public class UserAccountController {
+
+ @Autowired
+ private UserAccountService service;
+
+ @PostMapping("/addUserAccount")
+ public Object addUserAccount(@RequestBody UserAccount userAccount) {
+ return service.addUserAccount(userAccount);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/dao/UserAccountDao.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/dao/UserAccountDao.java
new file mode 100644
index 0000000000..c49c5220f4
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/dao/UserAccountDao.java
@@ -0,0 +1,31 @@
+package com.baeldung.spring.servicevalidation.dao;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.stereotype.Service;
+
+import com.baeldung.spring.servicevalidation.domain.UserAccount;
+
+@Service
+public class UserAccountDao {
+
+ private Map DB = new HashMap();
+
+ public String addUserAccount(UserAccount useraccount) {
+ DB.put(useraccount.getName(), useraccount);
+ return "success";
+ }
+
+ public Collection getAllUserAccounts() {
+
+ Collection list = DB.values();
+ if (list.isEmpty()) {
+ list.addAll(DB.values());
+ }
+ return list;
+
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/domain/UserAccount.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/domain/UserAccount.java
new file mode 100644
index 0000000000..5b0e795a8a
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/domain/UserAccount.java
@@ -0,0 +1,77 @@
+package com.baeldung.spring.servicevalidation.domain;
+
+import javax.validation.Valid;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+public class UserAccount {
+
+ @NotNull(message = "Password must be between 4 to 15 characters")
+ @Size(min = 4, max = 15)
+ private String password;
+
+ @NotBlank(message = "Name must not be blank")
+ private String name;
+
+ @Min(value = 18, message = "Age should not be less than 18")
+ private int age;
+
+ @NotBlank(message = "Phone must not be blank")
+ private String phone;
+
+ @Valid
+ @NotNull(message = "UserAddress must not be blank")
+ private UserAddress useraddress;
+
+ public UserAddress getUseraddress() {
+ return useraddress;
+ }
+
+ public void setUseraddress(UserAddress useraddress) {
+ this.useraddress = useraddress;
+ }
+
+ public UserAccount() {
+
+ }
+
+ public UserAccount(String email, String password, String name, int age) {
+ this.password = password;
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ public String getPhone() {
+ return phone;
+ }
+
+ public void setPhone(String phone) {
+ this.phone = phone;
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/domain/UserAddress.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/domain/UserAddress.java
new file mode 100644
index 0000000000..cd149dc5f5
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/domain/UserAddress.java
@@ -0,0 +1,18 @@
+package com.baeldung.spring.servicevalidation.domain;
+
+import javax.validation.constraints.NotBlank;
+
+public class UserAddress {
+
+ @NotBlank
+ private String countryCode;
+
+ public String getCountryCode() {
+ return countryCode;
+ }
+
+ public void setCountryCode(String countryCode) {
+ this.countryCode = countryCode;
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/service/UserAccountService.java b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/service/UserAccountService.java
new file mode 100644
index 0000000000..417e9a32b7
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validation/src/main/java/com/baeldung/spring/servicevalidation/service/UserAccountService.java
@@ -0,0 +1,42 @@
+package com.baeldung.spring.servicevalidation.service;
+
+import java.util.Set;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import javax.validation.Validator;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.baeldung.spring.servicevalidation.dao.UserAccountDao;
+import com.baeldung.spring.servicevalidation.domain.UserAccount;
+
+@Service
+public class UserAccountService {
+
+ @Autowired
+ private Validator validator;
+
+ @Autowired
+ private UserAccountDao dao;
+
+ public String addUserAccount(UserAccount useraccount) {
+
+ Set> violations = validator.validate(useraccount);
+
+ if (!violations.isEmpty()) {
+ StringBuilder sb = new StringBuilder();
+ for (ConstraintViolation constraintViolation : violations) {
+ sb.append(constraintViolation.getMessage());
+ }
+
+ dao.addUserAccount(useraccount);
+
+ throw new ConstraintViolationException("Error occurred: " + sb.toString(), violations);
+ }
+
+ return "Account for " + useraccount.getName() + " Added!";
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-validation/src/test/java/com/baeldung/SpringContextTest.java b/spring-boot-modules/spring-boot-validation/src/test/java/com/baeldung/SpringContextTest.java
new file mode 100644
index 0000000000..f4076a7756
--- /dev/null
+++ b/spring-boot-modules/spring-boot-validation/src/test/java/com/baeldung/SpringContextTest.java
@@ -0,0 +1,14 @@
+package com.baeldung;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import com.baeldung.spring.servicevalidation.SpringServiceLayerValidationApp;
+
+@SpringBootTest(classes = SpringServiceLayerValidationApp.class)
+public class SpringContextTest {
+
+ @Test
+ public void whenSpringContextIsBootstrapped_thenNoExceptions() {
+ }
+}
diff --git a/spring-cloud/spring-cloud-openfeign/README.md b/spring-cloud/spring-cloud-openfeign/README.md
index bcfd769d0c..5d3dc060c7 100644
--- a/spring-cloud/spring-cloud-openfeign/README.md
+++ b/spring-cloud/spring-cloud-openfeign/README.md
@@ -3,3 +3,4 @@
- [Introduction to Spring Cloud OpenFeign](https://www.baeldung.com/spring-cloud-openfeign)
- [Differences Between Netflix Feign and OpenFeign](https://www.baeldung.com/netflix-feign-vs-openfeign)
- [File Upload With Open Feign](https://www.baeldung.com/java-feign-file-upload)
+- [Feign Logging Configuration](https://www.baeldung.com/java-feign-logging)
diff --git a/testing-modules/testing-libraries-2/README.md b/testing-modules/testing-libraries-2/README.md
index 868d8f307d..7cc08a8140 100644
--- a/testing-modules/testing-libraries-2/README.md
+++ b/testing-modules/testing-libraries-2/README.md
@@ -3,3 +3,4 @@
- [Guide to the System Rules Library](https://www.baeldung.com/java-system-rules-junit)
- [Guide to the System Stubs Library](https://www.baeldung.com/java-system-stubs)
- [Code Coverage with SonarQube and JaCoCo](https://www.baeldung.com/sonarqube-jacoco-code-coverage)
+- [Exclusions from Jacoco Report](https://www.baeldung.com/jacoco-report-exclude)
diff --git a/testing-modules/testing-libraries-2/lombok.config b/testing-modules/testing-libraries-2/lombok.config
new file mode 100644
index 0000000000..7a21e88040
--- /dev/null
+++ b/testing-modules/testing-libraries-2/lombok.config
@@ -0,0 +1 @@
+lombok.addLombokGeneratedAnnotation = true
diff --git a/testing-modules/testing-libraries-2/pom.xml b/testing-modules/testing-libraries-2/pom.xml
index 5a57dc0958..d914fcfb86 100644
--- a/testing-modules/testing-libraries-2/pom.xml
+++ b/testing-modules/testing-libraries-2/pom.xml
@@ -13,6 +13,12 @@
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ provided
+
org.assertj
assertj-core
@@ -85,6 +91,13 @@
org.jacoco
jacoco-maven-plugin
${jacoco.version}
+
+
+ com/baeldung/**/ExcludedPOJO.class
+ com/baeldung/**/*DTO.*
+ **/config/*
+
+
jacoco-initialize
diff --git a/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/config/AppConfig.java b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/config/AppConfig.java
new file mode 100644
index 0000000000..26bfe7b196
--- /dev/null
+++ b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/config/AppConfig.java
@@ -0,0 +1,11 @@
+package com.baeldung.jacocoexclusions.config;
+
+import com.baeldung.jacocoexclusions.service.ProductService;
+
+public class AppConfig {
+
+ public ProductService productService() {
+ return new ProductService();
+ }
+
+}
diff --git a/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/domain/Product.java b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/domain/Product.java
new file mode 100644
index 0000000000..5606107371
--- /dev/null
+++ b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/domain/Product.java
@@ -0,0 +1,12 @@
+package com.baeldung.jacocoexclusions.domain;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Builder
+@Data
+public class Product {
+ private int id;
+ private String name;
+
+}
diff --git a/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/dto/ExcludedPOJO.java b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/dto/ExcludedPOJO.java
new file mode 100644
index 0000000000..27b461f70e
--- /dev/null
+++ b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/dto/ExcludedPOJO.java
@@ -0,0 +1,4 @@
+package com.baeldung.jacocoexclusions.dto;
+
+public class ExcludedPOJO {
+}
diff --git a/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/dto/ProductDTO.java b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/dto/ProductDTO.java
new file mode 100644
index 0000000000..fb0ec05621
--- /dev/null
+++ b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/dto/ProductDTO.java
@@ -0,0 +1,4 @@
+package com.baeldung.jacocoexclusions.dto;
+
+public class ProductDTO {
+}
diff --git a/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/generated/Customer.java b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/generated/Customer.java
new file mode 100644
index 0000000000..cab70467e3
--- /dev/null
+++ b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/generated/Customer.java
@@ -0,0 +1,11 @@
+package com.baeldung.jacocoexclusions.generated;
+
+@Generated
+public class Customer {
+ // everything in this class will be excluded from jacoco report because of @Generated
+
+ @Override
+ public String toString() {
+ return "Customer{}";
+ }
+}
diff --git a/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/generated/Generated.java b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/generated/Generated.java
new file mode 100644
index 0000000000..93be21e32d
--- /dev/null
+++ b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/generated/Generated.java
@@ -0,0 +1,15 @@
+package com.baeldung.jacocoexclusions.generated;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Documented
+@Retention(RUNTIME)
+@Target({TYPE, METHOD})
+public @interface Generated {
+}
\ No newline at end of file
diff --git a/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/service/CustomerService.java b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/service/CustomerService.java
new file mode 100644
index 0000000000..889153ba0a
--- /dev/null
+++ b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/service/CustomerService.java
@@ -0,0 +1,16 @@
+package com.baeldung.jacocoexclusions.service;
+
+import com.baeldung.jacocoexclusions.generated.Generated;
+
+public class CustomerService {
+
+ //this method will be excluded from coverage due to @Generated.
+ @Generated
+ public String getProductId() {
+ return "An ID";
+ }
+
+ public String getCustomerName() {
+ return "some name";
+ }
+}
diff --git a/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/service/ProductService.java b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/service/ProductService.java
new file mode 100644
index 0000000000..c87295e642
--- /dev/null
+++ b/testing-modules/testing-libraries-2/src/main/java/com/baeldung/jacocoexclusions/service/ProductService.java
@@ -0,0 +1,9 @@
+package com.baeldung.jacocoexclusions.service;
+
+public class ProductService {
+ private static final double DISCOUNT = 0.25;
+
+ public double getSalePrice(double originalPrice) {
+ return originalPrice - originalPrice * DISCOUNT;
+ }
+}
diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/jacocoexclusions/service/CustomerServiceUnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/jacocoexclusions/service/CustomerServiceUnitTest.java
new file mode 100644
index 0000000000..b35f92ca20
--- /dev/null
+++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/jacocoexclusions/service/CustomerServiceUnitTest.java
@@ -0,0 +1,14 @@
+package com.baeldung.jacocoexclusions.service;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+class CustomerServiceUnitTest {
+
+ @Test
+ public void givenCustomer_whenGetCustomer_thenReturnNewCustomer() {
+ CustomerService customerService = new CustomerService();
+ assertNotNull(customerService.getCustomerName());
+ }
+}
diff --git a/testing-modules/testing-libraries-2/src/test/java/com/baeldung/jacocoexclusions/service/ProductServiceUnitTest.java b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/jacocoexclusions/service/ProductServiceUnitTest.java
new file mode 100644
index 0000000000..609be33640
--- /dev/null
+++ b/testing-modules/testing-libraries-2/src/test/java/com/baeldung/jacocoexclusions/service/ProductServiceUnitTest.java
@@ -0,0 +1,15 @@
+package com.baeldung.jacocoexclusions.service;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class ProductServiceUnitTest {
+
+ @Test
+ public void givenOriginalPrice_whenGetSalePrice_thenReturnsDiscountedPrice() {
+ ProductService productService = new ProductService();
+ double salePrice = productService.getSalePrice(100);
+ assertEquals(salePrice, 75);
+ }
+}