(), { i, _, acc -> acc + i })
+ assertEquals(listOf(2,1,0), reversedIndexes)
+ }
+
+
+}
\ No newline at end of file
diff --git a/gradle/gradle-employee-app/.gitignore b/gradle/gradle-employee-app/.gitignore
new file mode 100644
index 0000000000..d347f664af
--- /dev/null
+++ b/gradle/gradle-employee-app/.gitignore
@@ -0,0 +1,3 @@
+/.idea
+/.gradle
+/build
diff --git a/gradle/gradle-employee-app/build.gradle b/gradle/gradle-employee-app/build.gradle
new file mode 100644
index 0000000000..19b80c0c4a
--- /dev/null
+++ b/gradle/gradle-employee-app/build.gradle
@@ -0,0 +1,38 @@
+
+plugins {
+ id 'java-library'
+ id 'application'
+}
+
+apply plugin: 'application'
+mainClassName = 'employee.EmployeeApp'
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+}
+
+println 'This is executed during configuration phase'
+
+task configured {
+ println 'The project is configured'
+}
+
+task wrapper(type: Wrapper){
+ gradleVersion = '5.3.1'
+}
+
+repositories {
+ jcenter()
+}
+
+dependencies {
+
+ compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.10'
+ testImplementation('junit:junit:4.13')
+ testRuntime('junit:junit:4.13')
+}
+test {
+ useJUnit()
+}
+
diff --git a/gradle/gradle-employee-app/src/main/java/employee/Employee.java b/gradle/gradle-employee-app/src/main/java/employee/Employee.java
new file mode 100644
index 0000000000..6940c8c28c
--- /dev/null
+++ b/gradle/gradle-employee-app/src/main/java/employee/Employee.java
@@ -0,0 +1,9 @@
+package employee;
+
+public class Employee {
+
+ String name;
+ String emailAddress;
+ int yearOfBirth;
+
+}
\ No newline at end of file
diff --git a/gradle/gradle-employee-app/src/main/java/employee/EmployeeApp.java b/gradle/gradle-employee-app/src/main/java/employee/EmployeeApp.java
new file mode 100644
index 0000000000..48ef9f5d61
--- /dev/null
+++ b/gradle/gradle-employee-app/src/main/java/employee/EmployeeApp.java
@@ -0,0 +1,16 @@
+package employee;
+
+public class EmployeeApp {
+
+ public static void main(String[] args){
+
+ Employee employee = new Employee();
+ employee.name = "John";
+ employee.emailAddress = "john@baeldung.com";
+ employee.yearOfBirth = 1978;
+ System.out.println("Name: " + employee.name);
+ System.out.println("Email Address: " + employee.emailAddress);
+ System.out.println("Year Of Birth:" + employee.yearOfBirth);
+ }
+
+}
diff --git a/gradle/gradle-employee-app/src/test/java/employee/EmployeeAppTest.java b/gradle/gradle-employee-app/src/test/java/employee/EmployeeAppTest.java
new file mode 100644
index 0000000000..013bcc35b6
--- /dev/null
+++ b/gradle/gradle-employee-app/src/test/java/employee/EmployeeAppTest.java
@@ -0,0 +1,31 @@
+package employee;
+
+import employee.Employee;
+import org.junit.*;
+import static org.junit.Assert.*;
+
+public class EmployeeAppTest {
+
+ @Test
+ public void testData(){
+
+ Employee testEmp = this.getEmployeeTest();
+
+ assertEquals(testEmp.name, "John");
+ assertEquals(testEmp.emailAddress, "john@baeldung.com");
+ assertEquals(testEmp.yearOfBirth, 1978);
+
+
+ }
+
+ private Employee getEmployeeTest(){
+
+ Employee employee = new Employee();
+ employee.name = "John";
+ employee.emailAddress = "john@baeldung.com";
+ employee.yearOfBirth = 1978;
+
+ return employee;
+ }
+
+}
\ No newline at end of file
diff --git a/gradle/settings.gradle b/gradle/settings.gradle
index f1d64de58a..59300f9281 100644
--- a/gradle/settings.gradle
+++ b/gradle/settings.gradle
@@ -1,10 +1,10 @@
rootProject.name = 'gradletutorial'
-
include 'greeting-library'
include 'greeting-library-java'
include 'greeter'
include 'gradletaskdemo'
include 'junit5'
+include 'gradle-employee-app'
println 'This will be executed during the initialization phase.'
diff --git a/jee-7/pom.xml b/jee-7/pom.xml
index 7352c6550a..9077aae1a6 100644
--- a/jee-7/pom.xml
+++ b/jee-7/pom.xml
@@ -256,10 +256,9 @@
- src/main/resources
-
- country.wsdl
-
+
+ http://localhost:8888/ws/country?wsdl
+
true
com.baeldung.soap.ws.client.generated
src/main/java
diff --git a/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/CountryServiceImplService.java b/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/CountryServiceImplService.java
index 09f4c29202..a6983938f5 100644
--- a/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/CountryServiceImplService.java
+++ b/jee-7/src/main/java/com/baeldung/soap/ws/client/generated/CountryServiceImplService.java
@@ -12,11 +12,11 @@ import javax.xml.ws.WebServiceFeature;
/**
* This class was generated by the JAX-WS RI.
- * JAX-WS RI 2.3.2
+ * JAX-WS RI 2.2.9-b130926.1035
* Generated source version: 2.2
*
*/
-@WebServiceClient(name = "CountryServiceImplService", targetNamespace = "http://server.ws.soap.baeldung.com/", wsdlLocation = "file:src/main/resources/country.wsdl")
+@WebServiceClient(name = "CountryServiceImplService", targetNamespace = "http://server.ws.soap.baeldung.com/", wsdlLocation = "http://localhost:8888/ws/country?wsdl")
public class CountryServiceImplService extends Service {
private final static URL COUNTRYSERVICEIMPLSERVICE_WSDL_LOCATION;
@@ -27,7 +27,7 @@ public class CountryServiceImplService extends Service {
URL url = null;
WebServiceException e = null;
try {
- url = new URL("file:src/main/resources/country.wsdl");
+ url = new URL("http://localhost:8888/ws/country?wsdl");
} catch (MalformedURLException ex) {
e = new WebServiceException(ex);
}
diff --git a/jee-7/src/main/resources/country.wsdl b/jee-7/src/main/resources/country.wsdl
deleted file mode 100644
index 4d41fce322..0000000000
--- a/jee-7/src/main/resources/country.wsdl
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/jee-7/src/test/java/com/baeldung/batch/understanding/CustomCheckPointUnitTest.java b/jee-7/src/test/java/com/baeldung/batch/understanding/CustomCheckPointUnitTest.java
index 744bdfc8f5..c607efeb24 100644
--- a/jee-7/src/test/java/com/baeldung/batch/understanding/CustomCheckPointUnitTest.java
+++ b/jee-7/src/test/java/com/baeldung/batch/understanding/CustomCheckPointUnitTest.java
@@ -1,20 +1,17 @@
package com.baeldung.batch.understanding;
-import static org.junit.jupiter.api.Assertions.*;
-import java.util.Map;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
import java.util.Properties;
+
import javax.batch.operations.JobOperator;
import javax.batch.runtime.BatchRuntime;
import javax.batch.runtime.BatchStatus;
import javax.batch.runtime.JobExecution;
-import javax.batch.runtime.Metric;
import javax.batch.runtime.StepExecution;
-import com.baeldung.batch.understanding.BatchTestHelper;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.Disabled;
-@Disabled("Should be fixed in BAEL-3812")
class CustomCheckPointUnitTest {
@Test
public void givenChunk_whenCustomCheckPoint_thenCommitCountIsThree() throws Exception {
diff --git a/jee-7/src/test/java/com/baeldung/batch/understanding/JobSequenceUnitTest.java b/jee-7/src/test/java/com/baeldung/batch/understanding/JobSequenceUnitTest.java
index 88b981df92..4b27e5f5ec 100644
--- a/jee-7/src/test/java/com/baeldung/batch/understanding/JobSequenceUnitTest.java
+++ b/jee-7/src/test/java/com/baeldung/batch/understanding/JobSequenceUnitTest.java
@@ -1,6 +1,8 @@
package com.baeldung.batch.understanding;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.ArrayList;
import java.util.List;
@@ -13,9 +15,7 @@ import javax.batch.runtime.JobExecution;
import javax.batch.runtime.StepExecution;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.Disabled;
-@Disabled("Should be fixed in BAEL-3812")
class JobSequenceUnitTest {
@Test
public void givenTwoSteps_thenBatch_CompleteWithSuccess() throws Exception {
diff --git a/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleBatchLetUnitTest.java b/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleBatchLetUnitTest.java
index 3babf9b5aa..788b75eb3e 100644
--- a/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleBatchLetUnitTest.java
+++ b/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleBatchLetUnitTest.java
@@ -1,17 +1,16 @@
package com.baeldung.batch.understanding;
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Properties;
import javax.batch.operations.JobOperator;
import javax.batch.runtime.BatchRuntime;
import javax.batch.runtime.BatchStatus;
import javax.batch.runtime.JobExecution;
-import java.util.Properties;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.junit.jupiter.api.Test;
-@Disabled("Should be fixed in BAEL-3812")
class SimpleBatchLetUnitTest {
@Test
public void givenBatchLet_thenBatch_CompleteWithSuccess() throws Exception {
diff --git a/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleChunkUnitTest.java b/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleChunkUnitTest.java
index 5871143fa3..9010c365a2 100644
--- a/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleChunkUnitTest.java
+++ b/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleChunkUnitTest.java
@@ -1,6 +1,7 @@
package com.baeldung.batch.understanding;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
import java.util.Map;
@@ -14,9 +15,7 @@ import javax.batch.runtime.Metric;
import javax.batch.runtime.StepExecution;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.Disabled;
-@Disabled("Should be fixed in BAEL-3812")
class SimpleChunkUnitTest {
@Test
public void givenChunk_thenBatch_CompletesWithSucess() throws Exception {
diff --git a/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleErrorChunkUnitTest.java b/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleErrorChunkUnitTest.java
index c53561a0c0..bc410aec8d 100644
--- a/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleErrorChunkUnitTest.java
+++ b/jee-7/src/test/java/com/baeldung/batch/understanding/SimpleErrorChunkUnitTest.java
@@ -1,19 +1,18 @@
package com.baeldung.batch.understanding;
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+import java.util.Properties;
import javax.batch.operations.JobOperator;
import javax.batch.runtime.BatchRuntime;
import javax.batch.runtime.BatchStatus;
import javax.batch.runtime.JobExecution;
import javax.batch.runtime.StepExecution;
-import java.util.List;
-import java.util.Properties;
-import static org.junit.Assert.assertEquals;
+import org.junit.jupiter.api.Test;
-@Disabled("Should be fixed in BAEL-3812")
class SimpleErrorChunkUnitTest {
@Test
diff --git a/jee-7/src/test/resources/jberet.properties b/jee-7/src/test/resources/jberet.properties
new file mode 100644
index 0000000000..e8b9907de5
--- /dev/null
+++ b/jee-7/src/test/resources/jberet.properties
@@ -0,0 +1 @@
+db-url=jdbc:h2:mem:jberet-repo;DB_CLOSE_DELAY=-1
\ No newline at end of file
diff --git a/jhipster/jhipster-uaa/gateway/pom.xml b/jhipster/jhipster-uaa/gateway/pom.xml
index 1b85877a9b..b417bd7b57 100644
--- a/jhipster/jhipster-uaa/gateway/pom.xml
+++ b/jhipster/jhipster-uaa/gateway/pom.xml
@@ -1013,7 +1013,7 @@
1.0.0
- 0.24.0-RC.0
+ 0.24.0
3.0.0
1.8
diff --git a/jhipster/jhipster-uaa/quotes/pom.xml b/jhipster/jhipster-uaa/quotes/pom.xml
index aacc6f8e36..f088ad2fd1 100644
--- a/jhipster/jhipster-uaa/quotes/pom.xml
+++ b/jhipster/jhipster-uaa/quotes/pom.xml
@@ -910,6 +910,6 @@
${project.basedir}/src/test/
- 0.24.0-RC.0
+ 0.24.0
diff --git a/jhipster/jhipster-uaa/uaa/pom.xml b/jhipster/jhipster-uaa/uaa/pom.xml
index 27a056820d..f9c1f226bb 100644
--- a/jhipster/jhipster-uaa/uaa/pom.xml
+++ b/jhipster/jhipster-uaa/uaa/pom.xml
@@ -835,7 +835,7 @@
1.0.0
- 0.24.0-RC.0
+ 0.24.0
3.0.0
1.8
diff --git a/kaniko/dockerfile b/kaniko/dockerfile
new file mode 100644
index 0000000000..0290bf16ed
--- /dev/null
+++ b/kaniko/dockerfile
@@ -0,0 +1,2 @@
+FROM ubuntu
+ENTRYPOINT ["/bin/bash", "-c", "echo hello"]
diff --git a/kaniko/pod.yaml b/kaniko/pod.yaml
new file mode 100644
index 0000000000..17f9a81b6d
--- /dev/null
+++ b/kaniko/pod.yaml
@@ -0,0 +1,19 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: kaniko
+spec:
+ containers:
+ - name: kaniko
+ image: gcr.io/kaniko-project/executor:latest
+ args: ["--dockerfile=/workspace/dockerfile",
+ "--context=dir://workspace",
+ "--no-push"]
+ volumeMounts:
+ - name: dockerfile-storage
+ mountPath: /workspace
+ restartPolicy: Never
+ volumes:
+ - name: dockerfile-storage
+ persistentVolumeClaim:
+ claimName: dockerfile-claim
diff --git a/kaniko/volume-claim.yaml b/kaniko/volume-claim.yaml
new file mode 100644
index 0000000000..7a1abbf05c
--- /dev/null
+++ b/kaniko/volume-claim.yaml
@@ -0,0 +1,11 @@
+kind: PersistentVolumeClaim
+apiVersion: v1
+metadata:
+ name: dockerfile-claim
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 8Gi
+ storageClassName: local-storage
diff --git a/kaniko/volume.yaml b/kaniko/volume.yaml
new file mode 100644
index 0000000000..e44663ec5a
--- /dev/null
+++ b/kaniko/volume.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: dockerfile
+ labels:
+ type: local
+spec:
+ capacity:
+ storage: 10Gi
+ accessModes:
+ - ReadWriteOnce
+ storageClassName: local-storage
+ hostPath:
+ path: /home/docker/kaniko # Path to the local mount directory that was setup
diff --git a/libraries-data-2/pom.xml b/libraries-data-2/pom.xml
index e6106c0fe3..73c5452f77 100644
--- a/libraries-data-2/pom.xml
+++ b/libraries-data-2/pom.xml
@@ -128,6 +128,21 @@
${awaitility.version}
test
+
+ org.rosuda.REngine
+ Rserve
+ ${rserve.version}
+
+
+ com.github.jbytecode
+ RCaller
+ ${rcaller.version}
+
+
+ org.renjin
+ renjin-script-engine
+ ${renjin.version}
+
@@ -137,6 +152,13 @@
http://repo.numericalmethod.com/maven/
default
+
+
+
+ bedatadriven
+ bedatadriven public repo
+ https://nexus.bedatadriven.com/content/groups/public/
+
@@ -153,6 +175,27 @@
3.6.2
1.7.25
3.0.0
+ RELEASE
+ 3.0
+ 1.8.1
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ com/baeldung/r/FastRMean.java
+
+
+ com/baeldung/r/FastRMeanUnitTest.java
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libraries-data-2/src/main/java/com/baeldung/r/FastRMean.java b/libraries-data-2/src/main/java/com/baeldung/r/FastRMean.java
new file mode 100644
index 0000000000..8348bfa403
--- /dev/null
+++ b/libraries-data-2/src/main/java/com/baeldung/r/FastRMean.java
@@ -0,0 +1,33 @@
+package com.baeldung.r;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+/**
+ * FastR showcase.
+ *
+ * @author Donato Rimenti
+ */
+public class FastRMean {
+
+ /**
+ * Invokes the customMean R function passing the given values as arguments.
+ *
+ * @param values the input to the mean script
+ * @return the result of the R script
+ */
+ public double mean(int[] values) {
+ Context polyglot = Context.newBuilder()
+ .allowAllAccess(true)
+ .build();
+ String meanScriptContent = RUtils.getMeanScriptContent();
+ polyglot.eval("R", meanScriptContent);
+ Value rBindings = polyglot.getBindings("R");
+ Value rInput = rBindings.getMember("c")
+ .execute(values);
+ return rBindings.getMember("customMean")
+ .execute(rInput)
+ .asDouble();
+ }
+
+}
\ No newline at end of file
diff --git a/libraries-data-2/src/main/java/com/baeldung/r/RCallerMean.java b/libraries-data-2/src/main/java/com/baeldung/r/RCallerMean.java
new file mode 100644
index 0000000000..99edb8c043
--- /dev/null
+++ b/libraries-data-2/src/main/java/com/baeldung/r/RCallerMean.java
@@ -0,0 +1,37 @@
+package com.baeldung.r;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+import com.github.rcaller.rstuff.RCaller;
+import com.github.rcaller.rstuff.RCallerOptions;
+import com.github.rcaller.rstuff.RCode;
+
+/**
+ * RCaller showcase.
+ *
+ * @author Donato Rimenti
+ */
+public class RCallerMean {
+
+ /**
+ * Invokes the customMean R function passing the given values as arguments.
+ *
+ * @param values the input to the mean script
+ * @return the result of the R script
+ * @throws IOException if any error occurs
+ * @throws URISyntaxException if any error occurs
+ */
+ public double mean(int[] values) throws IOException, URISyntaxException {
+ String fileContent = RUtils.getMeanScriptContent();
+ RCode code = RCode.create();
+ code.addRCode(fileContent);
+ code.addIntArray("input", values);
+ code.addRCode("result <- customMean(input)");
+ RCaller caller = RCaller.create(code, RCallerOptions.create());
+ caller.runAndReturnResult("result");
+ return caller.getParser()
+ .getAsDoubleArray("result")[0];
+ }
+
+}
\ No newline at end of file
diff --git a/libraries-data-2/src/main/java/com/baeldung/r/RUtils.java b/libraries-data-2/src/main/java/com/baeldung/r/RUtils.java
new file mode 100644
index 0000000000..a9393cdcc2
--- /dev/null
+++ b/libraries-data-2/src/main/java/com/baeldung/r/RUtils.java
@@ -0,0 +1,33 @@
+package com.baeldung.r;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Collectors;
+
+/**
+ * Utility class for loading the script.R content.
+ *
+ * @author Donato Rimenti
+ */
+public class RUtils {
+
+ /**
+ * Loads the script.R and returns its content as a string.
+ *
+ * @return the script.R content as a string
+ * @throws IOException if any error occurs
+ * @throws URISyntaxException if any error occurs
+ */
+ static String getMeanScriptContent() throws IOException, URISyntaxException {
+ URI rScriptUri = RUtils.class.getClassLoader()
+ .getResource("script.R")
+ .toURI();
+ Path inputScript = Paths.get(rScriptUri);
+ return Files.lines(inputScript)
+ .collect(Collectors.joining());
+ }
+}
\ No newline at end of file
diff --git a/libraries-data-2/src/main/java/com/baeldung/r/RenjinMean.java b/libraries-data-2/src/main/java/com/baeldung/r/RenjinMean.java
new file mode 100644
index 0000000000..4576ec5fb4
--- /dev/null
+++ b/libraries-data-2/src/main/java/com/baeldung/r/RenjinMean.java
@@ -0,0 +1,36 @@
+package com.baeldung.r;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+import javax.script.ScriptException;
+
+import org.renjin.script.RenjinScriptEngine;
+import org.renjin.sexp.DoubleArrayVector;
+
+/**
+ * Renjin showcase.
+ *
+ * @author Donato Rimenti
+ */
+public class RenjinMean {
+
+ /**
+ * Invokes the customMean R function passing the given values as arguments.
+ *
+ * @param values the input to the mean script
+ * @return the result of the R script
+ * @throws IOException if any error occurs
+ * @throws URISyntaxException if any error occurs
+ * @throws ScriptException if any error occurs
+ */
+ public double mean(int[] values) throws IOException, URISyntaxException, ScriptException {
+ RenjinScriptEngine engine = new RenjinScriptEngine();
+ String meanScriptContent = RUtils.getMeanScriptContent();
+ engine.put("input", values);
+ engine.eval(meanScriptContent);
+ DoubleArrayVector result = (DoubleArrayVector) engine.eval("customMean(input)");
+ return result.asReal();
+ }
+
+}
\ No newline at end of file
diff --git a/libraries-data-2/src/main/java/com/baeldung/r/RserveMean.java b/libraries-data-2/src/main/java/com/baeldung/r/RserveMean.java
new file mode 100644
index 0000000000..1aaa7fa847
--- /dev/null
+++ b/libraries-data-2/src/main/java/com/baeldung/r/RserveMean.java
@@ -0,0 +1,30 @@
+package com.baeldung.r;
+
+import org.rosuda.REngine.REXPMismatchException;
+import org.rosuda.REngine.REngineException;
+import org.rosuda.REngine.Rserve.RConnection;
+
+/**
+ * Rserve showcase.
+ *
+ * @author Donato Rimenti
+ */
+public class RserveMean {
+
+ /**
+ * Connects to the Rserve istance listening on 127.0.0.1:6311 and invokes the
+ * customMean R function passing the given values as arguments.
+ *
+ * @param values the input to the mean script
+ * @return the result of the R script
+ * @throws REngineException if any error occurs
+ * @throws REXPMismatchException if any error occurs
+ */
+ public double mean(int[] values) throws REngineException, REXPMismatchException {
+ RConnection c = new RConnection();
+ c.assign("input", values);
+ return c.eval("customMean(input)")
+ .asDouble();
+ }
+
+}
\ No newline at end of file
diff --git a/libraries-data-2/src/test/java/com/baeldung/r/FastRMeanUnitTest.java b/libraries-data-2/src/test/java/com/baeldung/r/FastRMeanUnitTest.java
new file mode 100644
index 0000000000..4e7426b75a
--- /dev/null
+++ b/libraries-data-2/src/test/java/com/baeldung/r/FastRMeanUnitTest.java
@@ -0,0 +1,29 @@
+package com.baeldung.r;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Test for {@link FastRMean}.
+ *
+ * @author Donato Rimenti
+ */
+@Ignore
+public class FastRMeanUnitTest {
+
+ /**
+ * Object to test.
+ */
+ private FastRMean fastrMean = new FastRMean();
+
+ /**
+ * Test for {@link FastRMeanUnitTest#mean(int[])}.
+ */
+ @Test
+ public void givenValues_whenMean_thenCorrect() {
+ int[] input = { 1, 2, 3, 4, 5 };
+ double result = fastrMean.mean(input);
+ Assert.assertEquals(3.0, result, 0.000001);
+ }
+}
\ No newline at end of file
diff --git a/libraries-data-2/src/test/java/com/baeldung/r/RCallerMeanIntegrationTest.java b/libraries-data-2/src/test/java/com/baeldung/r/RCallerMeanIntegrationTest.java
new file mode 100644
index 0000000000..ce6b3a4332
--- /dev/null
+++ b/libraries-data-2/src/test/java/com/baeldung/r/RCallerMeanIntegrationTest.java
@@ -0,0 +1,37 @@
+package com.baeldung.r;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+import javax.script.ScriptException;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Test for {@link RCallerMean}.
+ *
+ * @author Donato Rimenti
+ */
+@Ignore
+public class RCallerMeanIntegrationTest {
+
+ /**
+ * Object to test.
+ */
+ private RCallerMean rcallerMean = new RCallerMean();
+
+ /**
+ * Test for {@link RCallerMeanIntegrationTest#mean(int[])}.
+ *
+ * @throws ScriptException if an error occurs
+ * @throws URISyntaxException if an error occurs
+ */
+ @Test
+ public void givenValues_whenMean_thenCorrect() throws IOException, URISyntaxException {
+ int[] input = { 1, 2, 3, 4, 5 };
+ double result = rcallerMean.mean(input);
+ Assert.assertEquals(3.0, result, 0.000001);
+ }
+}
\ No newline at end of file
diff --git a/libraries-data-2/src/test/java/com/baeldung/r/RenjinMeanUnitTest.java b/libraries-data-2/src/test/java/com/baeldung/r/RenjinMeanUnitTest.java
new file mode 100644
index 0000000000..f52d37d614
--- /dev/null
+++ b/libraries-data-2/src/test/java/com/baeldung/r/RenjinMeanUnitTest.java
@@ -0,0 +1,37 @@
+package com.baeldung.r;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+import javax.script.ScriptException;
+
+import org.junit.Test;
+
+import org.junit.Assert;
+
+/**
+ * Test for {@link RenjinMean}.
+ *
+ * @author Donato Rimenti
+ */
+public class RenjinMeanUnitTest {
+
+ /**
+ * Object to test.
+ */
+ private RenjinMean renjinMean = new RenjinMean();
+
+ /**
+ * Test for {@link RenjinMeanUnitTest#mean(int[])}.
+ *
+ * @throws ScriptException if an error occurs
+ * @throws URISyntaxException if an error occurs
+ * @throws IOException if an error occurs
+ */
+ @Test
+ public void givenValues_whenMean_thenCorrect() throws IOException, URISyntaxException, ScriptException {
+ int[] input = { 1, 2, 3, 4, 5 };
+ double result = renjinMean.mean(input);
+ Assert.assertEquals(3.0, result, 0.000001);
+ }
+}
\ No newline at end of file
diff --git a/libraries-data-2/src/test/java/com/baeldung/r/RserveMeanIntegrationTest.java b/libraries-data-2/src/test/java/com/baeldung/r/RserveMeanIntegrationTest.java
new file mode 100644
index 0000000000..23d42bd8e9
--- /dev/null
+++ b/libraries-data-2/src/test/java/com/baeldung/r/RserveMeanIntegrationTest.java
@@ -0,0 +1,34 @@
+package com.baeldung.r;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.rosuda.REngine.REXPMismatchException;
+import org.rosuda.REngine.REngineException;
+
+/**
+ * Test for {@link RserveMean}.
+ *
+ * @author Donato Rimenti
+ */
+@Ignore
+public class RserveMeanIntegrationTest {
+
+ /**
+ * Object to test.
+ */
+ private RserveMean rserveMean = new RserveMean();
+
+ /**
+ * Test for {@link RserveMeanIntegrationTest#mean(int[])}.
+ *
+ * @throws REXPMismatchException if an error occurs
+ * @throws REngineException if an error occurs
+ */
+ @Test
+ public void givenValues_whenMean_thenCorrect() throws REngineException, REXPMismatchException {
+ int[] input = { 1, 2, 3, 4, 5 };
+ double result = rserveMean.mean(input);
+ Assert.assertEquals(3.0, result, 0.000001);
+ }
+}
\ No newline at end of file
diff --git a/libraries-data-2/src/test/resources/script.R b/libraries-data-2/src/test/resources/script.R
new file mode 100644
index 0000000000..08f859cc3d
--- /dev/null
+++ b/libraries-data-2/src/test/resources/script.R
@@ -0,0 +1,3 @@
+customMean <- function(vector) {
+ mean(vector)
+}
\ No newline at end of file
diff --git a/maven-java-11/README.md b/maven-java-11/README.md
deleted file mode 100644
index b923518825..0000000000
--- a/maven-java-11/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-## Maven and Java 11
-
-This module contains articles about Maven with Java 11+.
-
-### Relevant Articles:
-
diff --git a/maven-java-11/multimodule-maven-project/daomodule/pom.xml b/maven-java-11/multimodule-maven-project/daomodule/pom.xml
deleted file mode 100644
index cbe0b4cb95..0000000000
--- a/maven-java-11/multimodule-maven-project/daomodule/pom.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
- 4.0.0
- com.baeldung.daomodule
- daomodule
- 1.0
- daomodule
- jar
-
-
- com.baeldung.multimodule-maven-project
- multimodule-maven-project
- 1.0
-
-
-
diff --git a/maven-java-11/multimodule-maven-project/daomodule/src/main/java/com/baeldung/dao/Dao.java b/maven-java-11/multimodule-maven-project/daomodule/src/main/java/com/baeldung/dao/Dao.java
deleted file mode 100644
index f86ae8abb3..0000000000
--- a/maven-java-11/multimodule-maven-project/daomodule/src/main/java/com/baeldung/dao/Dao.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.baeldung.dao;
-
-import java.util.List;
-import java.util.Optional;
-
-public interface Dao {
-
- Optional findById(int id);
-
- List findAll();
-
-}
diff --git a/maven-java-11/multimodule-maven-project/daomodule/src/main/java/module-info.java b/maven-java-11/multimodule-maven-project/daomodule/src/main/java/module-info.java
deleted file mode 100644
index 072d7ad007..0000000000
--- a/maven-java-11/multimodule-maven-project/daomodule/src/main/java/module-info.java
+++ /dev/null
@@ -1,3 +0,0 @@
-module com.baeldung.dao {
- exports com.baeldung.dao;
-}
diff --git a/maven-java-11/multimodule-maven-project/entitiymodule/pom.xml b/maven-java-11/multimodule-maven-project/entitiymodule/pom.xml
deleted file mode 100644
index 228619ed74..0000000000
--- a/maven-java-11/multimodule-maven-project/entitiymodule/pom.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
- 4.0.0
- com.baeldung.entitymodule
- entitymodule
- 1.0
- entitymodule
- jar
-
-
- com.baeldung.multimodule-maven-project
- multimodule-maven-project
- 1.0
-
-
-
- 11
- 11
-
-
-
diff --git a/maven-java-11/multimodule-maven-project/entitiymodule/src/main/java/com/baeldung/entity/User.java b/maven-java-11/multimodule-maven-project/entitiymodule/src/main/java/com/baeldung/entity/User.java
deleted file mode 100644
index 22022a2e6d..0000000000
--- a/maven-java-11/multimodule-maven-project/entitiymodule/src/main/java/com/baeldung/entity/User.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.baeldung.entity;
-
-public class User {
-
- private final String name;
-
- public User(String name) {
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
-
- @Override
- public String toString() {
- return "User{" + "name=" + name + '}';
- }
-}
diff --git a/maven-java-11/multimodule-maven-project/entitiymodule/src/main/java/module-info.java b/maven-java-11/multimodule-maven-project/entitiymodule/src/main/java/module-info.java
deleted file mode 100644
index 67a3097352..0000000000
--- a/maven-java-11/multimodule-maven-project/entitiymodule/src/main/java/module-info.java
+++ /dev/null
@@ -1,3 +0,0 @@
-module com.baeldung.entity {
- exports com.baeldung.entity;
-}
diff --git a/maven-java-11/multimodule-maven-project/mainppmodule/pom.xml b/maven-java-11/multimodule-maven-project/mainppmodule/pom.xml
deleted file mode 100644
index a4a6575906..0000000000
--- a/maven-java-11/multimodule-maven-project/mainppmodule/pom.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
- 4.0.0
- com.baeldung.mainappmodule
- mainappmodule
- 1.0
- mainappmodule
- jar
-
-
- com.baeldung.multimodule-maven-project
- multimodule-maven-project
- 1.0
- 1.0
- 1.0
- 1.0
-
-
-
-
- com.baeldung.entitymodule
- entitymodule
- ${entitymodule.version}
-
-
- com.baeldung.daomodule
- daomodule
- ${daomodule.version}
-
-
- com.baeldung.userdaomodule
- userdaomodule
- ${userdaomodule.version}
-
-
-
-
diff --git a/maven-java-11/multimodule-maven-project/mainppmodule/src/main/java/com/baeldung/mainapp/Application.java b/maven-java-11/multimodule-maven-project/mainppmodule/src/main/java/com/baeldung/mainapp/Application.java
deleted file mode 100644
index 0c0df7461b..0000000000
--- a/maven-java-11/multimodule-maven-project/mainppmodule/src/main/java/com/baeldung/mainapp/Application.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.baeldung.mainapp;
-
-import com.baeldung.dao.Dao;
-import com.baeldung.entity.User;
-import com.baeldung.userdao.UserDao;
-import java.util.HashMap;
-import java.util.Map;
-
-public class Application {
-
- public static void main(String[] args) {
- Map users = new HashMap<>();
- users.put(1, new User("Julie"));
- users.put(2, new User("David"));
- Dao userDao = new UserDao(users);
- userDao.findAll().forEach(System.out::println);
- }
-
-}
diff --git a/maven-java-11/multimodule-maven-project/mainppmodule/src/main/java/module-info.java b/maven-java-11/multimodule-maven-project/mainppmodule/src/main/java/module-info.java
deleted file mode 100644
index c688fcf7de..0000000000
--- a/maven-java-11/multimodule-maven-project/mainppmodule/src/main/java/module-info.java
+++ /dev/null
@@ -1,6 +0,0 @@
-module com.baeldung.mainapp {
- requires com.baeldung.entity;
- requires com.baeldung.userdao;
- requires com.baeldung.dao;
- uses com.baeldung.dao.Dao;
-}
diff --git a/maven-java-11/multimodule-maven-project/pom.xml b/maven-java-11/multimodule-maven-project/pom.xml
deleted file mode 100644
index 65f5b7a814..0000000000
--- a/maven-java-11/multimodule-maven-project/pom.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
- 4.0.0
- com.baeldung.multimodule-maven-project
- multimodule-maven-project
- 1.0
- multimodule-maven-project
- pom
-
-
- com.baeldung.maven-java-11
- maven-java-11
- 1.0
-
-
-
- entitymodule
- daomodule
- userdaomodule
- mainappmodule
-
-
-
-
-
- junit
- junit
- ${junit.version}
- test
-
-
- org.assertj
- assertj-core
- ${assertj.version}
- test
-
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- ${compiler.plugin.version}
-
- ${source.version}
- ${target.version}
-
-
-
-
-
-
-
- UTF-8
- 4.12
- 3.12.2
- 3.8.0
- 11
- 11
-
-
-
diff --git a/maven-java-11/multimodule-maven-project/userdaomodule/pom.xml b/maven-java-11/multimodule-maven-project/userdaomodule/pom.xml
deleted file mode 100644
index cf6ea85cb5..0000000000
--- a/maven-java-11/multimodule-maven-project/userdaomodule/pom.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
- 4.0.0
- com.baeldung.userdaomodule
- userdaomodule
- 1.0
- userdaomodule
- jar
-
-
- com.baeldung.multimodule-maven-project
- multimodule-maven-project
- 1.0
-
-
-
-
- com.baeldung.entitymodule
- entitymodule
- ${entitymodule.version}1.0
-
-
- com.baeldung.daomodule
- daomodule
- ${daomodule.version}
-
-
- junit
- junit
- test
-
-
-
-
- 1.0
- 1.0
-
-
-
diff --git a/maven-java-11/multimodule-maven-project/userdaomodule/src/main/java/com/baeldung/userdao/UserDao.java b/maven-java-11/multimodule-maven-project/userdaomodule/src/main/java/com/baeldung/userdao/UserDao.java
deleted file mode 100644
index 1f1ea38a60..0000000000
--- a/maven-java-11/multimodule-maven-project/userdaomodule/src/main/java/com/baeldung/userdao/UserDao.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.baeldung.userdao;
-
-import com.baeldung.dao.Dao;
-import com.baeldung.entity.User;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-
-public class UserDao implements Dao {
-
- private final Map users;
-
- public UserDao() {
- users = new HashMap<>();
- }
-
- public UserDao(Map users) {
- this.users = users;
- }
-
- @Override
- public List findAll() {
- return new ArrayList<>(users.values());
- }
-
- @Override
- public Optional findById(int id) {
- return Optional.ofNullable(users.get(id));
- }
-}
\ No newline at end of file
diff --git a/maven-java-11/multimodule-maven-project/userdaomodule/src/main/java/module-info.java b/maven-java-11/multimodule-maven-project/userdaomodule/src/main/java/module-info.java
deleted file mode 100644
index f1cb217e23..0000000000
--- a/maven-java-11/multimodule-maven-project/userdaomodule/src/main/java/module-info.java
+++ /dev/null
@@ -1,6 +0,0 @@
-module com.baeldung.userdao {
- requires com.baeldung.entity;
- requires com.baeldung.dao;
- provides com.baeldung.dao.Dao with com.baeldung.userdao.UserDao;
- exports com.baeldung.userdao;
-}
diff --git a/maven-java-11/multimodule-maven-project/userdaomodule/src/test/java/com/baeldung/userdao/test/UserDaoUnitTest.java b/maven-java-11/multimodule-maven-project/userdaomodule/src/test/java/com/baeldung/userdao/test/UserDaoUnitTest.java
deleted file mode 100644
index 191d17ff32..0000000000
--- a/maven-java-11/multimodule-maven-project/userdaomodule/src/test/java/com/baeldung/userdao/test/UserDaoUnitTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.baeldung.userdao.test;
-
-import com.baeldung.dao.Dao;
-import com.baeldung.entity.User;
-import com.baeldung.userdao.UserDao;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import static org.junit.Assert.*;
-import static org.hamcrest.CoreMatchers.*;
-import org.junit.Before;
-import org.junit.Test;
-
-public class UserDaoUnitTest {
-
- private Dao userDao;
-
- @Before
- public void setUpUserDaoInstance() {
- Map users = new HashMap<>();
- users.put(1, new User("Julie"));
- users.put(2, new User("David"));
- userDao = new UserDao(users);
- }
-
- @Test
- public void givenUserDaoIntance_whenCalledFindById_thenCorrect() {
- assertThat(userDao.findById(1), isA(Optional.class));
- }
-
- @Test
- public void givenUserDaoIntance_whenCalledFindAll_thenCorrect() {
- assertThat(userDao.findAll(), isA(List.class));
- }
-}
diff --git a/maven-java-11/pom.xml b/maven-java-11/pom.xml
deleted file mode 100644
index 10e80365c8..0000000000
--- a/maven-java-11/pom.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
- 4.0.0
- com.baeldung.maven-java-11
- maven-java-11
- 1.0
- maven-java-11
- pom
-
-
- com.baeldung
- parent-modules
- 1.0.0-SNAPSHOT
-
-
-
- multimodule-maven-project
-
-
-
- UTF-8
- 11
- 11
-
-
-
diff --git a/patterns/solid/src/main/java/com/baeldung/s/TextManipulator.java b/patterns/solid/src/main/java/com/baeldung/s/TextManipulator.java
new file mode 100644
index 0000000000..a6b32a0ff9
--- /dev/null
+++ b/patterns/solid/src/main/java/com/baeldung/s/TextManipulator.java
@@ -0,0 +1,35 @@
+package com.baeldung.s;
+
+public class TextManipulator {
+ private String text;
+
+ public TextManipulator(String text) {
+ this.text = text;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void appendText(String newText) {
+ text = text.concat(newText);
+ }
+
+ public void findWordAndReplace(String word, String replacementWord) {
+ if (text.contains(word)) {
+ text = text.replace(word, replacementWord);
+ } else System.out.println("Word you want to replace is not found in the text");
+ }
+
+ public void findWordAndDelete(String word) {
+ if (text.contains(word)) {
+ text = text.replace(word, "");
+ } else System.out.println("Word you want to delete is not found in the text");
+ }
+
+ /*
+ * Bad practice when implementing SRP principle, not in the scope of this class
+ public void printText() {
+ System.out.println(textManipulator.getText());
+ }*/
+}
diff --git a/patterns/solid/src/main/java/com/baeldung/s/TextPrinter.java b/patterns/solid/src/main/java/com/baeldung/s/TextPrinter.java
new file mode 100644
index 0000000000..d6a413e7ac
--- /dev/null
+++ b/patterns/solid/src/main/java/com/baeldung/s/TextPrinter.java
@@ -0,0 +1,23 @@
+package com.baeldung.s;
+
+import java.util.Arrays;
+
+public class TextPrinter {
+ TextManipulator textManipulator;
+
+ public TextPrinter(TextManipulator textManipulator) {
+ this.textManipulator = textManipulator;
+ }
+
+ public void printText() {
+ System.out.println(textManipulator.getText());
+ }
+
+ public void printOutEachWordOfText() {
+ System.out.println(Arrays.toString(textManipulator.getText().split(" ")));
+ }
+
+ public void printRangeOfCharacters(int startingIndex, int endIndex) {
+ System.out.println(textManipulator.getText().substring(startingIndex, endIndex));
+ }
+}
diff --git a/persistence-modules/java-jpa-2/pom.xml b/persistence-modules/java-jpa-2/pom.xml
index d4532c32b8..ab5bb39dfc 100644
--- a/persistence-modules/java-jpa-2/pom.xml
+++ b/persistence-modules/java-jpa-2/pom.xml
@@ -139,7 +139,7 @@
5.4.14.Final
- 2.7.4-RC1
+ 2.7.4
42.2.5
2.2
3.11.1
diff --git a/persistence-modules/java-jpa/pom.xml b/persistence-modules/java-jpa/pom.xml
index 762c541d96..3601721dac 100644
--- a/persistence-modules/java-jpa/pom.xml
+++ b/persistence-modules/java-jpa/pom.xml
@@ -106,7 +106,7 @@
5.4.0.Final
- 2.7.4-RC1
+ 2.7.4
42.2.5
2.2
3.3.3
diff --git a/persistence-modules/spring-data-dynamodb/pom.xml b/persistence-modules/spring-data-dynamodb/pom.xml
index fceceb40ba..377e35b635 100644
--- a/persistence-modules/spring-data-dynamodb/pom.xml
+++ b/persistence-modules/spring-data-dynamodb/pom.xml
@@ -9,9 +9,9 @@
com.baeldung
- parent-boot-1
+ parent-boot-2
0.0.1-SNAPSHOT
- ../../parent-boot-1
+ ../../parent-boot-2
@@ -19,7 +19,7 @@
org.springframework.data
spring-data-releasetrain
- Hopper-SR10
+ Lovelace-SR16
pom
import
@@ -174,7 +174,7 @@
com.baeldung.Application
4.3.4.RELEASE
4.5.2
- 4.4.1
+ 5.1.0
1.11.64
3.3.7-1
1.0.392
diff --git a/persistence-modules/spring-data-dynamodb/src/main/java/com/baeldung/spring/data/dynamodb/config/DynamoDBConfig.java b/persistence-modules/spring-data-dynamodb/src/main/java/com/baeldung/spring/data/dynamodb/config/DynamoDBConfig.java
index 9278c0a12e..7e97e6b383 100644
--- a/persistence-modules/spring-data-dynamodb/src/main/java/com/baeldung/spring/data/dynamodb/config/DynamoDBConfig.java
+++ b/persistence-modules/spring-data-dynamodb/src/main/java/com/baeldung/spring/data/dynamodb/config/DynamoDBConfig.java
@@ -44,8 +44,8 @@ public class DynamoDBConfig {
return new BasicAWSCredentials(amazonAWSAccessKey, amazonAWSSecretKey);
}
- @Bean(name = "mvcHandlerMappingIntrospector")
- public HandlerMappingIntrospector mvcHandlerMappingIntrospector() {
+ @Bean(name = "mvcHandlerMappingIntrospectorCustom")
+ public HandlerMappingIntrospector mvcHandlerMappingIntrospectorCustom() {
return new HandlerMappingIntrospector(context);
}
}
diff --git a/persistence-modules/spring-data-dynamodb/src/main/java/com/baeldung/spring/data/dynamodb/repositories/ProductInfoRepository.java b/persistence-modules/spring-data-dynamodb/src/main/java/com/baeldung/spring/data/dynamodb/repositories/ProductInfoRepository.java
index da47f033b6..6e8b493c3b 100644
--- a/persistence-modules/spring-data-dynamodb/src/main/java/com/baeldung/spring/data/dynamodb/repositories/ProductInfoRepository.java
+++ b/persistence-modules/spring-data-dynamodb/src/main/java/com/baeldung/spring/data/dynamodb/repositories/ProductInfoRepository.java
@@ -1,12 +1,13 @@
package com.baeldung.spring.data.dynamodb.repositories;
-import com.baeldung.spring.data.dynamodb.model.ProductInfo;
+import java.util.Optional;
+
import org.socialsignin.spring.data.dynamodb.repository.EnableScan;
import org.springframework.data.repository.CrudRepository;
-import java.util.List;
+import com.baeldung.spring.data.dynamodb.model.ProductInfo;
@EnableScan
public interface ProductInfoRepository extends CrudRepository {
- List findById(String id);
+ Optional findById(String id);
}
diff --git a/persistence-modules/spring-data-mongodb/README.md b/persistence-modules/spring-data-mongodb/README.md
index c4f21dffc0..381bf83fa8 100644
--- a/persistence-modules/spring-data-mongodb/README.md
+++ b/persistence-modules/spring-data-mongodb/README.md
@@ -13,3 +13,12 @@
- [Spring Data Annotations](http://www.baeldung.com/spring-data-annotations)
- [Spring Data MongoDB Transactions](https://www.baeldung.com/spring-data-mongodb-transactions )
- [ZonedDateTime with Spring Data MongoDB](https://www.baeldung.com/spring-data-mongodb-zoneddatetime)
+
+
+## Spring Data MongoDB Live Testing
+
+
+There are 3 scripts to simplify running live tests:
+1. [`live-test-setup.sh`](src/live-test/resources/live-test-setup.sh) builds a docker image with the necessary setup and runs it. The environment is ready, when the log stops - it takes approximately 30 seconds.
+2. [`live-test.sh`](src/live-test/resources/live-test.sh) runs the live tests (but no other tests).
+3. [`live-test-teardown.sh`](src/live-test/resources/live-test-teardown.sh) stops and removes the docker image.
diff --git a/persistence-modules/spring-data-mongodb/src/live-test/resources/Dockerfile b/persistence-modules/spring-data-mongodb/src/live-test/resources/Dockerfile
new file mode 100644
index 0000000000..9e3634feb0
--- /dev/null
+++ b/persistence-modules/spring-data-mongodb/src/live-test/resources/Dockerfile
@@ -0,0 +1,8 @@
+FROM mongo:4.2.1
+
+COPY init-session.js /docker-entrypoint-initdb.d/
+
+EXPOSE 27017
+
+HEALTHCHECK --interval=5s --timeout=3s --start-period=10s CMD mongo db.stats()
+CMD ["mongod", "--replSet", "rs0"]
diff --git a/persistence-modules/spring-data-mongodb/src/live-test/resources/init-session.js b/persistence-modules/spring-data-mongodb/src/live-test/resources/init-session.js
new file mode 100644
index 0000000000..2e968884cc
--- /dev/null
+++ b/persistence-modules/spring-data-mongodb/src/live-test/resources/init-session.js
@@ -0,0 +1 @@
+rs.initiate();
diff --git a/persistence-modules/spring-data-mongodb/src/live-test/resources/live-test-setup.sh b/persistence-modules/spring-data-mongodb/src/live-test/resources/live-test-setup.sh
new file mode 100644
index 0000000000..78968d51aa
--- /dev/null
+++ b/persistence-modules/spring-data-mongodb/src/live-test/resources/live-test-setup.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+docker image build -t spring-data-mongodb:live-test .
+
+docker run -p 27017:27017 --name spring-data-mongodb-live-test spring-data-mongodb:live-test
diff --git a/persistence-modules/spring-data-mongodb/src/live-test/resources/live-test-teardown.sh b/persistence-modules/spring-data-mongodb/src/live-test/resources/live-test-teardown.sh
new file mode 100644
index 0000000000..a29163bc7a
--- /dev/null
+++ b/persistence-modules/spring-data-mongodb/src/live-test/resources/live-test-teardown.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+docker stop spring-data-mongodb-live-test
+docker rm spring-data-mongodb-live-test
diff --git a/persistence-modules/spring-data-mongodb/src/live-test/resources/live-test.sh b/persistence-modules/spring-data-mongodb/src/live-test/resources/live-test.sh
new file mode 100644
index 0000000000..307a68a3bd
--- /dev/null
+++ b/persistence-modules/spring-data-mongodb/src/live-test/resources/live-test.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+mvn clean compile test -P live-all -f ../../../pom.xml
diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionalLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionalLiveTest.java
index bafcd770ec..6cd9657006 100644
--- a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionalLiveTest.java
+++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/transaction/MongoTransactionalLiveTest.java
@@ -62,24 +62,6 @@ public class MongoTransactionalLiveTest {
}
}
- @Test(expected = MongoCommandException.class)
- @Transactional
- public void whenCountDuringMongoTransaction_thenException() {
- userRepository.save(new User("John", 30));
- userRepository.save(new User("Ringo", 35));
- userRepository.count();
- }
-
- @Test
- @Transactional
- public void whenQueryDuringMongoTransaction_thenSuccess() {
- userRepository.save(new User("Jane", 20));
- userRepository.save(new User("Nick", 33));
- List users = mongoTemplate.find(new Query(), User.class);
-
- assertTrue(users.size() > 1);
- }
-
// ==== Using test instead of before and after due to @transactional doesn't allow list collection
@Test
diff --git a/pom.xml b/pom.xml
index 02d1ab6cd2..f2c23a94ae 100644
--- a/pom.xml
+++ b/pom.xml
@@ -652,6 +652,7 @@
spring-core
spring-core-2
spring-core-3
+ spring-core-4
spring-cucumber
spring-data-rest
@@ -812,7 +813,8 @@
libraries
vaadin
- vavr
+ vavr
+ vavr-2
@@ -1157,6 +1159,7 @@
spring-core
spring-core-2
spring-core-3
+ spring-core-4
spring-cucumber
spring-data-rest
@@ -1310,10 +1313,41 @@
libraries
vaadin
- vavr
+ vavr
+ vavr-2
+
+
+ live-all
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ **/SpringContextTest.java
+ **/*UnitTest.java
+ **/*IntegrationTest.java
+ **/*IntTest.java
+ **/*LongRunningUnitTest.java
+ **/*ManualTest.java
+ **/*JdbcTest.java
+
+
+ **/*LiveTest.java
+
+
+
+
+
+
+
+
+
diff --git a/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/SpringBootGroovyApplication.groovy b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/SpringBootGroovyApplication.groovy
new file mode 100644
index 0000000000..4912b75a66
--- /dev/null
+++ b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/SpringBootGroovyApplication.groovy
@@ -0,0 +1,13 @@
+package com.baeldung.springwithgroovy
+
+import org.springframework.boot.SpringApplication
+import org.springframework.boot.autoconfigure.SpringBootApplication
+
+import com.baeldung.springwithgroovy.SpringBootGroovyApplication
+
+@SpringBootApplication
+class SpringBootGroovyApplication {
+ static void main(String[] args) {
+ SpringApplication.run SpringBootGroovyApplication, args
+ }
+}
diff --git a/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/controller/TodoController.groovy b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/controller/TodoController.groovy
new file mode 100644
index 0000000000..9c6aee20d3
--- /dev/null
+++ b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/controller/TodoController.groovy
@@ -0,0 +1,48 @@
+package com.baeldung.springwithgroovy.controller
+
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.web.bind.annotation.DeleteMapping
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.PathVariable
+import org.springframework.web.bind.annotation.PostMapping
+import org.springframework.web.bind.annotation.PutMapping
+import org.springframework.web.bind.annotation.RequestBody
+import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.RequestMethod
+import org.springframework.web.bind.annotation.RestController
+
+import com.baeldung.springwithgroovy.entity.Todo
+import com.baeldung.springwithgroovy.service.TodoService
+
+@RestController
+@RequestMapping('todo')
+public class TodoController {
+
+ @Autowired
+ TodoService todoService
+
+ @GetMapping
+ List getAllTodoList(){
+ todoService.findAll()
+ }
+
+ @PostMapping
+ Todo saveTodo(@RequestBody Todo todo){
+ todoService.saveTodo todo
+ }
+
+ @PutMapping
+ Todo updateTodo(@RequestBody Todo todo){
+ todoService.updateTodo todo
+ }
+
+ @DeleteMapping('/{todoId}')
+ deleteTodo(@PathVariable Integer todoId){
+ todoService.deleteTodo todoId
+ }
+
+ @GetMapping('/{todoId}')
+ Todo getTodoById(@PathVariable Integer todoId){
+ todoService.findById todoId
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/entity/Todo.groovy b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/entity/Todo.groovy
new file mode 100644
index 0000000000..000d981701
--- /dev/null
+++ b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/entity/Todo.groovy
@@ -0,0 +1,23 @@
+package com.baeldung.springwithgroovy.entity
+
+import javax.persistence.Column
+import javax.persistence.Entity
+import javax.persistence.GeneratedValue
+import javax.persistence.GenerationType
+import javax.persistence.Id
+import javax.persistence.Table
+
+@Entity
+@Table(name = 'todo')
+class Todo {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ Integer id
+
+ @Column
+ String task
+
+ @Column
+ Boolean isCompleted
+
+}
diff --git a/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/repository/TodoRepository.groovy b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/repository/TodoRepository.groovy
new file mode 100644
index 0000000000..eb58cc0791
--- /dev/null
+++ b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/repository/TodoRepository.groovy
@@ -0,0 +1,9 @@
+package com.baeldung.springwithgroovy.repository
+
+import org.springframework.data.jpa.repository.JpaRepository
+import org.springframework.stereotype.Repository
+
+import com.baeldung.springwithgroovy.entity.Todo
+
+@Repository
+interface TodoRepository extends JpaRepository {}
\ No newline at end of file
diff --git a/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/service/TodoService.groovy b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/service/TodoService.groovy
new file mode 100644
index 0000000000..c57af34cde
--- /dev/null
+++ b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/service/TodoService.groovy
@@ -0,0 +1,16 @@
+package com.baeldung.springwithgroovy.service
+
+import com.baeldung.springwithgroovy.entity.Todo
+
+interface TodoService {
+
+ List findAll()
+
+ Todo findById(Integer todoId)
+
+ Todo saveTodo(Todo todo)
+
+ Todo updateTodo(Todo todo)
+
+ Todo deleteTodo(Integer todoId)
+}
diff --git a/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/service/impl/TodoServiceImpl.groovy b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/service/impl/TodoServiceImpl.groovy
new file mode 100644
index 0000000000..943c1c6944
--- /dev/null
+++ b/spring-boot-groovy/src/main/groovy/com/baeldung/springwithgroovy/service/impl/TodoServiceImpl.groovy
@@ -0,0 +1,40 @@
+package com.baeldung.springwithgroovy.service.impl
+
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.stereotype.Service
+
+import com.baeldung.springwithgroovy.entity.Todo
+import com.baeldung.springwithgroovy.repository.TodoRepository
+import com.baeldung.springwithgroovy.service.TodoService
+
+@Service
+class TodoServiceImpl implements TodoService {
+
+ @Autowired
+ TodoRepository todoRepository
+
+ @Override
+ List findAll() {
+ todoRepository.findAll()
+ }
+
+ @Override
+ Todo findById(Integer todoId) {
+ todoRepository.findById todoId get()
+ }
+
+ @Override
+ Todo saveTodo(Todo todo){
+ todoRepository.save todo
+ }
+
+ @Override
+ Todo updateTodo(Todo todo){
+ todoRepository.save todo
+ }
+
+ @Override
+ Todo deleteTodo(Integer todoId){
+ todoRepository.deleteById todoId
+ }
+}
diff --git a/spring-boot-groovy/src/test/groovy/com/baeldung/springwithgroovy/TodoAppUnitTest.groovy b/spring-boot-groovy/src/test/groovy/com/baeldung/springwithgroovy/TodoAppUnitTest.groovy
new file mode 100644
index 0000000000..bf8b0ff27f
--- /dev/null
+++ b/spring-boot-groovy/src/test/groovy/com/baeldung/springwithgroovy/TodoAppUnitTest.groovy
@@ -0,0 +1,97 @@
+package com.baeldung.springwithgroovy
+
+import static org.junit.jupiter.api.Assertions.assertEquals
+import static org.junit.jupiter.api.Assertions.assertTrue
+
+import org.junit.BeforeClass
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+import org.springframework.test.context.event.annotation.BeforeTestClass
+import org.springframework.test.context.junit4.SpringRunner
+
+import com.baeldung.springwithgroovy.entity.Todo
+
+import io.restassured.RestAssured
+import io.restassured.response.Response
+
+class TodoAppUnitTest {
+ static API_ROOT = 'http://localhost:8081/todo'
+ static readingTodoId
+ static writingTodoId
+
+ @BeforeClass
+ static void populateDummyData() {
+ Todo readingTodo = new Todo(task: 'Reading', isCompleted: false)
+ Todo writingTodo = new Todo(task: 'Writing', isCompleted: false)
+
+ final Response readingResponse =
+ RestAssured.given()
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .body(readingTodo).post(API_ROOT)
+
+ Todo cookingTodoResponse = readingResponse.as Todo.class
+ readingTodoId = cookingTodoResponse.getId()
+
+ final Response writingResponse =
+ RestAssured.given()
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .body(writingTodo).post(API_ROOT)
+
+ Todo writingTodoResponse = writingResponse.as Todo.class
+ writingTodoId = writingTodoResponse.getId()
+ }
+
+ @Test
+ void whenGetAllTodoList_thenOk(){
+ final Response response = RestAssured.get(API_ROOT)
+
+ assertEquals HttpStatus.OK.value(),response.getStatusCode()
+ assertTrue response.as(List.class).size() > 0
+ }
+
+ @Test
+ void whenGetTodoById_thenOk(){
+ final Response response =
+ RestAssured.get("$API_ROOT/$readingTodoId")
+
+ assertEquals HttpStatus.OK.value(),response.getStatusCode()
+ Todo todoResponse = response.as Todo.class
+ assertEquals readingTodoId,todoResponse.getId()
+ }
+
+ @Test
+ void whenUpdateTodoById_thenOk(){
+ Todo todo = new Todo(id:readingTodoId, isCompleted: true)
+ final Response response =
+ RestAssured.given()
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .body(todo).put(API_ROOT)
+
+ assertEquals HttpStatus.OK.value(),response.getStatusCode()
+ Todo todoResponse = response.as Todo.class
+ assertTrue todoResponse.getIsCompleted()
+ }
+
+ @Test
+ void whenDeleteTodoById_thenOk(){
+ final Response response =
+ RestAssured.given()
+ .delete("$API_ROOT/$writingTodoId")
+
+ assertEquals HttpStatus.OK.value(),response.getStatusCode()
+ }
+
+ @Test
+ void whenSaveTodo_thenOk(){
+ Todo todo = new Todo(task: 'Blogging', isCompleted: false)
+ final Response response =
+ RestAssured.given()
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .body(todo).post(API_ROOT)
+
+ assertEquals HttpStatus.OK.value(),response.getStatusCode()
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-autoconfigure/pom.xml b/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-autoconfigure/pom.xml
index 0bba2936a7..532f45cf3e 100644
--- a/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-autoconfigure/pom.xml
+++ b/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-autoconfigure/pom.xml
@@ -63,7 +63,7 @@
UTF-8
- 1.5.2.RELEASE
+ 2.2.6.RELEASE
0.0.1-SNAPSHOT
diff --git a/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-autoconfigure/src/test/java/org/baeldung/SpringContextTest.java b/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-autoconfigure/src/test/java/com/baeldung/SpringContextTest.java
similarity index 100%
rename from spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-autoconfigure/src/test/java/org/baeldung/SpringContextTest.java
rename to spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-autoconfigure/src/test/java/com/baeldung/SpringContextTest.java
diff --git a/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/pom.xml b/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/pom.xml
index 818ce5c107..8d328b88be 100644
--- a/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/pom.xml
+++ b/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/pom.xml
@@ -8,9 +8,9 @@
com.baeldung
- parent-boot-1
+ parent-boot-2
0.0.1-SNAPSHOT
- ../../../parent-boot-1
+ ../../../parent-boot-2
diff --git a/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/src/test/java/org/baeldung/SpringContextTest.java b/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/src/test/java/com/baeldung/SpringContextTest.java
similarity index 100%
rename from spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/src/test/java/org/baeldung/SpringContextTest.java
rename to spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-sample-app/src/test/java/com/baeldung/SpringContextTest.java
diff --git a/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-starter/pom.xml b/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-starter/pom.xml
index ba2b4101e8..0e8fb4cbc9 100644
--- a/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-starter/pom.xml
+++ b/spring-boot-modules/spring-boot-custom-starter/greeter-spring-boot-starter/pom.xml
@@ -51,7 +51,7 @@
UTF-8
0.0.1-SNAPSHOT
- 1.5.2.RELEASE
+ 2.2.6.RELEASE
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-custom-starter/greeter/pom.xml b/spring-boot-modules/spring-boot-custom-starter/greeter/pom.xml
index 89119e2e99..47296990aa 100644
--- a/spring-boot-modules/spring-boot-custom-starter/greeter/pom.xml
+++ b/spring-boot-modules/spring-boot-custom-starter/greeter/pom.xml
@@ -8,9 +8,9 @@
com.baeldung
- parent-boot-1
+ parent-boot-2
0.0.1-SNAPSHOT
- ../../../parent-boot-1
+ ../../../parent-boot-2
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-property-exp/property-exp-custom-config/pom.xml b/spring-boot-modules/spring-boot-property-exp/property-exp-custom-config/pom.xml
index 8ea9c8366d..e38a2742d5 100644
--- a/spring-boot-modules/spring-boot-property-exp/property-exp-custom-config/pom.xml
+++ b/spring-boot-modules/spring-boot-property-exp/property-exp-custom-config/pom.xml
@@ -24,6 +24,12 @@
spring-boot-starter-test
${spring-boot.version}
test
+
+
+ org.junit.vintage
+ junit-vintage-engine
+
+
@@ -72,7 +78,7 @@
- 1.5.10.RELEASE
+ 2.2.6.RELEASE
Custom Property Value
2.7
1.6.0
diff --git a/spring-boot-modules/spring-boot-property-exp/property-exp-custom-config/src/test/java/org/baeldung/SpringContextTest.java b/spring-boot-modules/spring-boot-property-exp/property-exp-custom-config/src/test/java/com/baeldung/SpringContextTest.java
similarity index 100%
rename from spring-boot-modules/spring-boot-property-exp/property-exp-custom-config/src/test/java/org/baeldung/SpringContextTest.java
rename to spring-boot-modules/spring-boot-property-exp/property-exp-custom-config/src/test/java/com/baeldung/SpringContextTest.java
diff --git a/spring-boot-modules/spring-boot-property-exp/property-exp-default-config/pom.xml b/spring-boot-modules/spring-boot-property-exp/property-exp-default-config/pom.xml
index aa5b8ef34a..79e194a3b5 100644
--- a/spring-boot-modules/spring-boot-property-exp/property-exp-default-config/pom.xml
+++ b/spring-boot-modules/spring-boot-property-exp/property-exp-default-config/pom.xml
@@ -9,9 +9,9 @@
com.baeldung
- parent-boot-1
+ parent-boot-2
0.0.1-SNAPSHOT
- ../../../parent-boot-1
+ ../../../parent-boot-2
diff --git a/spring-boot-modules/spring-boot-property-exp/property-exp-default-config/src/test/java/org/baeldung/SpringContextTest.java b/spring-boot-modules/spring-boot-property-exp/property-exp-default-config/src/test/java/com/baeldung/SpringContextTest.java
similarity index 100%
rename from spring-boot-modules/spring-boot-property-exp/property-exp-default-config/src/test/java/org/baeldung/SpringContextTest.java
rename to spring-boot-modules/spring-boot-property-exp/property-exp-default-config/src/test/java/com/baeldung/SpringContextTest.java
diff --git a/spring-core-4/README.md b/spring-core-4/README.md
new file mode 100644
index 0000000000..f882c77179
--- /dev/null
+++ b/spring-core-4/README.md
@@ -0,0 +1,7 @@
+## Spring Core
+
+This module contains articles about core Spring functionality
+
+## Relevant Articles:
+
+- More articles: [[<-- prev]](/spring-core-3)
diff --git a/spring-core-4/pom.xml b/spring-core-4/pom.xml
new file mode 100644
index 0000000000..53f7ca6912
--- /dev/null
+++ b/spring-core-4/pom.xml
@@ -0,0 +1,63 @@
+
+
+ 4.0.0
+ spring-core-4
+ spring-core-4
+
+
+ com.baeldung
+ parent-spring-5
+ 0.0.1-SNAPSHOT
+ ../parent-spring-5
+
+
+
+
+ org.springframework
+ spring-context
+ ${spring.version}
+
+
+ org.springframework
+ spring-core
+ ${spring.version}
+
+
+ org.springframework
+ spring-test
+ ${spring.version}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ ${junit-jupiter.version}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ ${junit-jupiter.version}
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${maven.surefire.version}
+
+
+
+
+
+ 2.22.1
+ 1.3.2
+ 2.2.2.RELEASE
+
+
+
\ No newline at end of file
diff --git a/spring-core-4/src/main/java/com/baeldung/factorymethod/Bar.java b/spring-core-4/src/main/java/com/baeldung/factorymethod/Bar.java
new file mode 100644
index 0000000000..22ef5b3429
--- /dev/null
+++ b/spring-core-4/src/main/java/com/baeldung/factorymethod/Bar.java
@@ -0,0 +1,18 @@
+package com.baeldung.factorymethod;
+
+public class Bar {
+
+ private String name;
+
+ public Bar(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/spring-core-4/src/main/java/com/baeldung/factorymethod/Foo.java b/spring-core-4/src/main/java/com/baeldung/factorymethod/Foo.java
new file mode 100644
index 0000000000..54bd0c9ff4
--- /dev/null
+++ b/spring-core-4/src/main/java/com/baeldung/factorymethod/Foo.java
@@ -0,0 +1,5 @@
+package com.baeldung.factorymethod;
+
+public class Foo {
+
+}
diff --git a/spring-core-4/src/main/java/com/baeldung/factorymethod/InstanceBarFactory.java b/spring-core-4/src/main/java/com/baeldung/factorymethod/InstanceBarFactory.java
new file mode 100644
index 0000000000..f834b82aee
--- /dev/null
+++ b/spring-core-4/src/main/java/com/baeldung/factorymethod/InstanceBarFactory.java
@@ -0,0 +1,8 @@
+package com.baeldung.factorymethod;
+
+public class InstanceBarFactory {
+
+ public Bar createInstance(String name) {
+ return new Bar(name);
+ }
+}
diff --git a/spring-core-4/src/main/java/com/baeldung/factorymethod/InstanceFooFactory.java b/spring-core-4/src/main/java/com/baeldung/factorymethod/InstanceFooFactory.java
new file mode 100644
index 0000000000..c3125d3339
--- /dev/null
+++ b/spring-core-4/src/main/java/com/baeldung/factorymethod/InstanceFooFactory.java
@@ -0,0 +1,8 @@
+package com.baeldung.factorymethod;
+
+public class InstanceFooFactory {
+
+ public Foo createInstance() {
+ return new Foo();
+ }
+}
diff --git a/spring-core-4/src/main/java/com/baeldung/factorymethod/SingletonBarFactory.java b/spring-core-4/src/main/java/com/baeldung/factorymethod/SingletonBarFactory.java
new file mode 100644
index 0000000000..93802819b1
--- /dev/null
+++ b/spring-core-4/src/main/java/com/baeldung/factorymethod/SingletonBarFactory.java
@@ -0,0 +1,11 @@
+package com.baeldung.factorymethod;
+
+public class SingletonBarFactory {
+
+ private static final Bar INSTANCE = new Bar("unnamed");
+
+ public static Bar createInstance(String name) {
+ INSTANCE.setName(name);
+ return INSTANCE;
+ }
+}
diff --git a/spring-core-4/src/main/java/com/baeldung/factorymethod/SingletonFooFactory.java b/spring-core-4/src/main/java/com/baeldung/factorymethod/SingletonFooFactory.java
new file mode 100644
index 0000000000..77d56cc7f6
--- /dev/null
+++ b/spring-core-4/src/main/java/com/baeldung/factorymethod/SingletonFooFactory.java
@@ -0,0 +1,10 @@
+package com.baeldung.factorymethod;
+
+public class SingletonFooFactory {
+
+ private static final Foo INSTANCE = new Foo();
+
+ public static Foo createInstance() {
+ return INSTANCE;
+ }
+}
diff --git a/spring-core-4/src/test/java/com/baeldung/factorymethod/InstanceBarFactoryIntegrationTest.java b/spring-core-4/src/test/java/com/baeldung/factorymethod/InstanceBarFactoryIntegrationTest.java
new file mode 100644
index 0000000000..b5728316e7
--- /dev/null
+++ b/spring-core-4/src/test/java/com/baeldung/factorymethod/InstanceBarFactoryIntegrationTest.java
@@ -0,0 +1,24 @@
+package com.baeldung.factorymethod;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("/factorymethod/instance-bar-config.xml")
+public class InstanceBarFactoryIntegrationTest {
+
+ @Autowired
+ private Bar instance;
+
+ @Test
+ public void givenValidInstanceFactoryConfig_whenCreateInstance_thenNameIsCorrect() {
+ assertNotNull(instance);
+ assertEquals("someName", instance.getName());
+ }
+}
diff --git a/spring-core-4/src/test/java/com/baeldung/factorymethod/InstanceFooFactoryIntegrationTest.java b/spring-core-4/src/test/java/com/baeldung/factorymethod/InstanceFooFactoryIntegrationTest.java
new file mode 100644
index 0000000000..6b1857c2f2
--- /dev/null
+++ b/spring-core-4/src/test/java/com/baeldung/factorymethod/InstanceFooFactoryIntegrationTest.java
@@ -0,0 +1,22 @@
+package com.baeldung.factorymethod;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("/factorymethod/instance-foo-config.xml")
+public class InstanceFooFactoryIntegrationTest {
+
+ @Autowired
+ private Foo foo;
+
+ @Test
+ public void givenValidInstanceFactoryConfig_whenCreateFooInstance_thenInstanceIsNotNull() {
+ assertNotNull(foo);
+ }
+}
diff --git a/spring-core-4/src/test/java/com/baeldung/factorymethod/SingletonBarFactoryIntegrationTest.java b/spring-core-4/src/test/java/com/baeldung/factorymethod/SingletonBarFactoryIntegrationTest.java
new file mode 100644
index 0000000000..403b46156b
--- /dev/null
+++ b/spring-core-4/src/test/java/com/baeldung/factorymethod/SingletonBarFactoryIntegrationTest.java
@@ -0,0 +1,24 @@
+package com.baeldung.factorymethod;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("/factorymethod/static-bar-config.xml")
+public class SingletonBarFactoryIntegrationTest {
+
+ @Autowired
+ private Bar instance;
+
+ @Test
+ public void givenValidStaticFactoryConfig_whenCreateInstance_thenNameIsCorrect() {
+ assertNotNull(instance);
+ assertEquals("someName", instance.getName());
+ }
+}
diff --git a/spring-core-4/src/test/java/com/baeldung/factorymethod/SingletonFooFactoryIntegrationTest.java b/spring-core-4/src/test/java/com/baeldung/factorymethod/SingletonFooFactoryIntegrationTest.java
new file mode 100644
index 0000000000..52154b81ab
--- /dev/null
+++ b/spring-core-4/src/test/java/com/baeldung/factorymethod/SingletonFooFactoryIntegrationTest.java
@@ -0,0 +1,22 @@
+package com.baeldung.factorymethod;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("/factorymethod/static-foo-config.xml")
+public class SingletonFooFactoryIntegrationTest {
+
+ @Autowired
+ private Foo singleton;
+
+ @Test
+ public void givenValidStaticFactoryConfig_whenCreateInstance_thenInstanceIsNotNull() {
+ assertNotNull(singleton);
+ }
+}
diff --git a/spring-core-4/src/test/resources/factorymethod/instance-bar-config.xml b/spring-core-4/src/test/resources/factorymethod/instance-bar-config.xml
new file mode 100644
index 0000000000..a4281aee4e
--- /dev/null
+++ b/spring-core-4/src/test/resources/factorymethod/instance-bar-config.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-core-4/src/test/resources/factorymethod/instance-foo-config.xml b/spring-core-4/src/test/resources/factorymethod/instance-foo-config.xml
new file mode 100644
index 0000000000..0f21f06f5a
--- /dev/null
+++ b/spring-core-4/src/test/resources/factorymethod/instance-foo-config.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-core-4/src/test/resources/factorymethod/static-bar-config.xml b/spring-core-4/src/test/resources/factorymethod/static-bar-config.xml
new file mode 100644
index 0000000000..2cacc293bc
--- /dev/null
+++ b/spring-core-4/src/test/resources/factorymethod/static-bar-config.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-core-4/src/test/resources/factorymethod/static-foo-config.xml b/spring-core-4/src/test/resources/factorymethod/static-foo-config.xml
new file mode 100644
index 0000000000..ffe1480638
--- /dev/null
+++ b/spring-core-4/src/test/resources/factorymethod/static-foo-config.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-mockito/pom.xml b/spring-mockito/pom.xml
index f3e0b04808..5d2cd7c445 100644
--- a/spring-mockito/pom.xml
+++ b/spring-mockito/pom.xml
@@ -28,7 +28,7 @@
- 2.21.0
+ 2.24.0
diff --git a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/controller/TaskController.java b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/controller/TaskController.java
index a084f14eca..67072b5d61 100644
--- a/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/controller/TaskController.java
+++ b/spring-security-modules/spring-security-core/src/main/java/com/baeldung/app/controller/TaskController.java
@@ -1,8 +1,15 @@
package com.baeldung.app.controller;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@@ -10,6 +17,8 @@ import org.springframework.web.bind.annotation.RequestMethod;
import com.baeldung.app.entity.Task;
import com.baeldung.app.service.TaskService;
+import javax.servlet.http.HttpServletRequest;
+
@Controller
@RequestMapping("api/tasks")
public class TaskController {
@@ -17,6 +26,9 @@ public class TaskController {
@Autowired
private TaskService taskService;
+ @Autowired(required = false)
+ private UserDetailsService userDetailsService;
+
@RequestMapping(method = RequestMethod.GET)
public ResponseEntity> findAllTasks() {
Iterable tasks = taskService.findAll();
@@ -30,4 +42,62 @@ public class TaskController {
return ResponseEntity.ok().body(tasks);
}
+
+ /**
+ * Example of restricting specific endpoints to specific roles using @PreAuthorize.
+ */
+ @GetMapping("/manager")
+ @PreAuthorize("hasRole('ROLE_MANAGER')")
+ public ResponseEntity> getAlManagerTasks() {
+ Iterable tasks = taskService.findAll();
+
+ return ResponseEntity.ok().body(tasks);
+ }
+
+ /**
+ * Example of restricting specific endpoints to specific roles using SecurityContext.
+ */
+ @GetMapping("/actuator")
+ public ResponseEntity> getAlActuatorTasks() {
+ Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+ if (auth != null && auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ACTUATOR")))
+ {
+ return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
+ }
+
+ Iterable tasks = taskService.findAll();
+
+ return ResponseEntity.ok().body(tasks);
+ }
+
+ /**
+ * Example of restricting specific endpoints to specific roles using UserDetailsService.
+ */
+ @GetMapping("/admin")
+ public ResponseEntity> getAlAdminTasks() {
+ if(userDetailsService != null) {
+ UserDetails details = userDetailsService.loadUserByUsername("pam");
+ if (details != null && details.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ADMIN"))) {
+ return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
+ }
+ }
+
+ Iterable tasks = taskService.findAll();
+
+ return ResponseEntity.ok().body(tasks);
+ }
+
+ /**
+ * Example of restricting specific endpoints to specific roles using HttpServletRequest.
+ */
+ @GetMapping("/admin2")
+ public ResponseEntity> getAlAdminTasksUsingServlet(HttpServletRequest request) {
+ if (!request.isUserInRole("ROLE_ADMIN")) {
+ return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
+ }
+
+ Iterable tasks = taskService.findAll();
+
+ return ResponseEntity.ok().body(tasks);
+ }
}
diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/CustomLogoutApplication.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/CustomLogoutApplication.java
new file mode 100644
index 0000000000..39d867b1f4
--- /dev/null
+++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/CustomLogoutApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.customlogouthandler;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class CustomLogoutApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(CustomLogoutApplication.class, args);
+ }
+
+}
diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/MvcConfiguration.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/MvcConfiguration.java
new file mode 100644
index 0000000000..c363effb4e
--- /dev/null
+++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/MvcConfiguration.java
@@ -0,0 +1,55 @@
+package com.baeldung.customlogouthandler;
+
+import javax.sql.DataSource;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
+
+import com.baeldung.customlogouthandler.web.CustomLogoutHandler;
+
+@Configuration
+@EnableWebSecurity
+public class MvcConfiguration extends WebSecurityConfigurerAdapter {
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Autowired
+ private CustomLogoutHandler logoutHandler;
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.httpBasic()
+ .and()
+ .authorizeRequests()
+ .antMatchers(HttpMethod.GET, "/user/**")
+ .hasRole("USER")
+ .and()
+ .logout()
+ .logoutUrl("/user/logout")
+ .addLogoutHandler(logoutHandler)
+ .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK))
+ .permitAll()
+ .and()
+ .csrf()
+ .disable()
+ .formLogin()
+ .disable();
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ auth.jdbcAuthentication()
+ .dataSource(dataSource)
+ .usersByUsernameQuery("select login, password, true from users where login=?")
+ .authoritiesByUsernameQuery("select login, role from users where login=?");
+ }
+
+}
diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/services/UserCache.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/services/UserCache.java
new file mode 100644
index 0000000000..b86edc0dee
--- /dev/null
+++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/services/UserCache.java
@@ -0,0 +1,35 @@
+package com.baeldung.customlogouthandler.services;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+import org.springframework.stereotype.Service;
+
+import com.baeldung.customlogouthandler.user.User;
+
+@Service
+public class UserCache {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ private final ConcurrentMap store = new ConcurrentHashMap<>(256);
+
+ public User getByUserName(String userName) {
+ return store.computeIfAbsent(userName, k -> entityManager.createQuery("from User where login=:login", User.class)
+ .setParameter("login", k)
+ .getSingleResult());
+ }
+
+ public void evictUser(String userName) {
+ store.remove(userName);
+ }
+
+ public int size() {
+ return store.size();
+ }
+
+}
diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/User.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/User.java
new file mode 100644
index 0000000000..ca3a998c5c
--- /dev/null
+++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/User.java
@@ -0,0 +1,61 @@
+package com.baeldung.customlogouthandler.user;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "users")
+public class User {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Integer id;
+
+ @Column(unique = true)
+ private String login;
+
+ private String password;
+
+ private String role;
+
+ private String language;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getLogin() {
+ return login;
+ }
+
+ public void setLogin(String login) {
+ this.login = login;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+}
diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/UserUtils.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/UserUtils.java
new file mode 100644
index 0000000000..aa9a521b01
--- /dev/null
+++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/user/UserUtils.java
@@ -0,0 +1,14 @@
+package com.baeldung.customlogouthandler.user;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+public class UserUtils {
+
+ public static String getAuthenticatedUserName() {
+ Authentication auth = SecurityContextHolder.getContext()
+ .getAuthentication();
+ return auth != null ? ((org.springframework.security.core.userdetails.User) auth.getPrincipal()).getUsername() : null;
+ }
+
+}
diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/CustomLogoutHandler.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/CustomLogoutHandler.java
new file mode 100644
index 0000000000..a89c9a570d
--- /dev/null
+++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/CustomLogoutHandler.java
@@ -0,0 +1,28 @@
+package com.baeldung.customlogouthandler.web;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.logout.LogoutHandler;
+import org.springframework.stereotype.Service;
+
+import com.baeldung.customlogouthandler.services.UserCache;
+import com.baeldung.customlogouthandler.user.UserUtils;
+
+@Service
+public class CustomLogoutHandler implements LogoutHandler {
+
+ private final UserCache userCache;
+
+ public CustomLogoutHandler(UserCache userCache) {
+ this.userCache = userCache;
+ }
+
+ @Override
+ public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
+ String userName = UserUtils.getAuthenticatedUserName();
+ userCache.evictUser(userName);
+ }
+
+}
diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/UserController.java b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/UserController.java
new file mode 100644
index 0000000000..b2d332a1bb
--- /dev/null
+++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/java/com/baeldung/customlogouthandler/web/UserController.java
@@ -0,0 +1,30 @@
+package com.baeldung.customlogouthandler.web;
+
+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 com.baeldung.customlogouthandler.services.UserCache;
+import com.baeldung.customlogouthandler.user.User;
+import com.baeldung.customlogouthandler.user.UserUtils;
+
+@Controller
+@RequestMapping(path = "/user")
+public class UserController {
+
+ private final UserCache userCache;
+
+ public UserController(UserCache userCache) {
+ this.userCache = userCache;
+ }
+
+ @GetMapping(path = "/language")
+ @ResponseBody
+ public String getLanguage() {
+ String userName = UserUtils.getAuthenticatedUserName();
+ User user = userCache.getByUserName(userName);
+ return user.getLanguage();
+ }
+
+}
diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/main/resources/application-customlogouthandler.properties b/spring-security-modules/spring-security-mvc-boot-2/src/main/resources/application-customlogouthandler.properties
new file mode 100644
index 0000000000..2cb766378d
--- /dev/null
+++ b/spring-security-modules/spring-security-mvc-boot-2/src/main/resources/application-customlogouthandler.properties
@@ -0,0 +1,5 @@
+spring.datasource.url=jdbc:postgresql://localhost:5432/test
+spring.datasource.username=test
+spring.datasource.password=test
+
+spring.jpa.hibernate.ddl-auto=create
\ No newline at end of file
diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/test/java/com/baeldung/customlogouthandler/CustomLogoutHandlerIntegrationTest.java b/spring-security-modules/spring-security-mvc-boot-2/src/test/java/com/baeldung/customlogouthandler/CustomLogoutHandlerIntegrationTest.java
new file mode 100644
index 0000000000..cd8a1a72d6
--- /dev/null
+++ b/spring-security-modules/spring-security-mvc-boot-2/src/test/java/com/baeldung/customlogouthandler/CustomLogoutHandlerIntegrationTest.java
@@ -0,0 +1,108 @@
+package com.baeldung.customlogouthandler;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+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.boot.web.server.LocalServerPort;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.jdbc.SqlGroup;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import com.baeldung.customlogouthandler.services.UserCache;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest(classes = { CustomLogoutApplication.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@SqlGroup({ @Sql(value = "classpath:customlogouthandler/before.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD), @Sql(value = "classpath:customlogouthandler/after.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) })
+@TestPropertySource(locations="classpath:customlogouthandler/application.properties")
+class CustomLogoutHandlerIntegrationTest {
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ @Autowired
+ private UserCache userCache;
+
+ @LocalServerPort
+ private int port;
+
+ @Test
+ public void whenLogin_thenUseUserCache() {
+ // User cache should be empty on start
+ assertThat(userCache.size()).isEqualTo(0);
+
+ // Request using first login
+ ResponseEntity response = restTemplate.withBasicAuth("user", "pass")
+ .getForEntity(getLanguageUrl(), String.class);
+
+ assertThat(response.getBody()).contains("english");
+
+ // User cache must contain the user
+ assertThat(userCache.size()).isEqualTo(1);
+
+ // Getting the session cookie
+ HttpHeaders requestHeaders = new HttpHeaders();
+ requestHeaders.add("Cookie", response.getHeaders()
+ .getFirst(HttpHeaders.SET_COOKIE));
+
+ // Request with the session cookie
+ response = restTemplate.exchange(getLanguageUrl(), HttpMethod.GET, new HttpEntity(requestHeaders), String.class);
+ assertThat(response.getBody()).contains("english");
+
+ // Logging out using the session cookies
+ response = restTemplate.exchange(getLogoutUrl(), HttpMethod.GET, new HttpEntity(requestHeaders), String.class);
+ assertThat(response.getStatusCode()
+ .value()).isEqualTo(200);
+ }
+
+ @Test
+ public void whenLogout_thenCacheIsEmpty() {
+ // User cache should be empty on start
+ assertThat(userCache.size()).isEqualTo(0);
+
+ // Request using first login
+ ResponseEntity response = restTemplate.withBasicAuth("user", "pass")
+ .getForEntity(getLanguageUrl(), String.class);
+
+ assertThat(response.getBody()).contains("english");
+
+ // User cache must contain the user
+ assertThat(userCache.size()).isEqualTo(1);
+
+ // Getting the session cookie
+ HttpHeaders requestHeaders = new HttpHeaders();
+ requestHeaders.add("Cookie", response.getHeaders()
+ .getFirst(HttpHeaders.SET_COOKIE));
+
+ // Logging out using the session cookies
+ response = restTemplate.exchange(getLogoutUrl(), HttpMethod.GET, new HttpEntity(requestHeaders), String.class);
+ assertThat(response.getStatusCode()
+ .value()).isEqualTo(200);
+
+ // User cache must be empty now
+ // this is the reaction on custom logout filter execution
+ assertThat(userCache.size()).isEqualTo(0);
+
+ // Assert unauthorized request
+ response = restTemplate.exchange(getLanguageUrl(), HttpMethod.GET, new HttpEntity(requestHeaders), String.class);
+ assertThat(response.getStatusCode()
+ .value()).isEqualTo(401);
+ }
+
+ private String getLanguageUrl() {
+ return "http://localhost:" + port + "/user/language";
+ }
+
+ private String getLogoutUrl() {
+ return "http://localhost:" + port + "/user/logout";
+ }
+
+}
diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/after.sql b/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/after.sql
new file mode 100644
index 0000000000..df6f312987
--- /dev/null
+++ b/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/after.sql
@@ -0,0 +1 @@
+delete from users;
\ No newline at end of file
diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/application.properties b/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/application.properties
new file mode 100644
index 0000000000..9edd853f2c
--- /dev/null
+++ b/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/application.properties
@@ -0,0 +1,5 @@
+spring.datasource.url=jdbc:postgresql://localhost:5432/test
+spring.datasource.username=test
+spring.datasource.password=test
+
+spring.jpa.hibernate.ddl-auto=create
diff --git a/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/before.sql b/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/before.sql
new file mode 100644
index 0000000000..bb0a85f613
--- /dev/null
+++ b/spring-security-modules/spring-security-mvc-boot-2/src/test/resources/customlogouthandler/before.sql
@@ -0,0 +1 @@
+insert into users (login, password, role, language) values ('user', '{noop}pass', 'ROLE_USER', 'english');
\ No newline at end of file
diff --git a/spring-soap/pom.xml b/spring-soap/pom.xml
index 9403b70636..d0987329c0 100644
--- a/spring-soap/pom.xml
+++ b/spring-soap/pom.xml
@@ -58,6 +58,28 @@
+
+
+ org.jvnet.jaxb2.maven2
+ maven-jaxb2-plugin
+ 0.14.0
+
+
+
+ generate
+
+
+
+
+ WSDL
+ ${project.basedir}/src/main/java
+ com.baeldung.springsoap.client.gen
+ ${project.basedir}/src/main/resources
+
+ countries.wsdl
+
+
+
diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/CountryClient.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/CountryClient.java
new file mode 100644
index 0000000000..e0b9172ece
--- /dev/null
+++ b/spring-soap/src/main/java/com/baeldung/springsoap/client/CountryClient.java
@@ -0,0 +1,26 @@
+package com.baeldung.springsoap.client;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
+
+import com.baeldung.springsoap.client.gen.GetCountryRequest;
+import com.baeldung.springsoap.client.gen.GetCountryResponse;
+
+public class CountryClient extends WebServiceGatewaySupport {
+
+ private static final Logger logger = LoggerFactory.getLogger(CountryClient.class);
+
+ public GetCountryResponse getCountry(String country) {
+
+ GetCountryRequest request = new GetCountryRequest();
+ request.setName(country);
+
+ logger.info("Requesting information for " + country);
+
+ GetCountryResponse response = (GetCountryResponse) getWebServiceTemplate().marshalSendAndReceive(request);
+
+ return response;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/CountryClientConfig.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/CountryClientConfig.java
new file mode 100644
index 0000000000..8dabdbc00d
--- /dev/null
+++ b/spring-soap/src/main/java/com/baeldung/springsoap/client/CountryClientConfig.java
@@ -0,0 +1,25 @@
+package com.baeldung.springsoap.client;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.oxm.jaxb.Jaxb2Marshaller;
+
+@Configuration
+public class CountryClientConfig {
+
+ @Bean
+ public Jaxb2Marshaller marshaller() {
+ Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
+ marshaller.setContextPath("com.baeldung.springsoap.client.gen");
+ return marshaller;
+ }
+
+ @Bean
+ public CountryClient countryClient(Jaxb2Marshaller marshaller) {
+ CountryClient client = new CountryClient();
+ client.setDefaultUri("http://localhost:8080/ws");
+ client.setMarshaller(marshaller);
+ client.setUnmarshaller(marshaller);
+ return client;
+ }
+}
\ No newline at end of file
diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Country.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Country.java
new file mode 100644
index 0000000000..e17dce55f9
--- /dev/null
+++ b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Country.java
@@ -0,0 +1,146 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.3.0
+// See https://javaee.github.io/jaxb-v2/
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2020.04.25 at 03:18:49 PM IST
+//
+
+
+package com.baeldung.springsoap.client.gen;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * Java class for country complex type.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ * <complexType name="country">
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * <element name="population" type="{http://www.w3.org/2001/XMLSchema}int"/>
+ * <element name="capital" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * <element name="currency" type="{http://www.baeldung.com/springsoap/gen}currency"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ *
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "country", propOrder = {
+ "name",
+ "population",
+ "capital",
+ "currency"
+})
+public class Country {
+
+ @XmlElement(required = true)
+ protected String name;
+ protected int population;
+ @XmlElement(required = true)
+ protected String capital;
+ @XmlElement(required = true)
+ @XmlSchemaType(name = "string")
+ protected Currency currency;
+
+ /**
+ * 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 population property.
+ *
+ */
+ public int getPopulation() {
+ return population;
+ }
+
+ /**
+ * Sets the value of the population property.
+ *
+ */
+ public void setPopulation(int value) {
+ this.population = value;
+ }
+
+ /**
+ * Gets the value of the capital property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getCapital() {
+ return capital;
+ }
+
+ /**
+ * Sets the value of the capital property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setCapital(String value) {
+ this.capital = value;
+ }
+
+ /**
+ * Gets the value of the currency property.
+ *
+ * @return
+ * possible object is
+ * {@link Currency }
+ *
+ */
+ public Currency getCurrency() {
+ return currency;
+ }
+
+ /**
+ * Sets the value of the currency property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Currency }
+ *
+ */
+ public void setCurrency(Currency value) {
+ this.currency = value;
+ }
+
+}
diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Currency.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Currency.java
new file mode 100644
index 0000000000..12fdef58c2
--- /dev/null
+++ b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Currency.java
@@ -0,0 +1,47 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.3.0
+// See https://javaee.github.io/jaxb-v2/
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2020.04.25 at 03:18:49 PM IST
+//
+
+
+package com.baeldung.springsoap.client.gen;
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * Java class for currency.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ * <simpleType name="currency">
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ * <enumeration value="GBP"/>
+ * <enumeration value="EUR"/>
+ * <enumeration value="PLN"/>
+ * </restriction>
+ * </simpleType>
+ *
+ *
+ */
+@XmlType(name = "currency")
+@XmlEnum
+public enum Currency {
+
+ GBP,
+ EUR,
+ PLN;
+
+ public String value() {
+ return name();
+ }
+
+ public static Currency fromValue(String v) {
+ return valueOf(v);
+ }
+
+}
diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryRequest.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryRequest.java
new file mode 100644
index 0000000000..5739ee3b96
--- /dev/null
+++ b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryRequest.java
@@ -0,0 +1,71 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.3.0
+// See https://javaee.github.io/jaxb-v2/
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2020.04.25 at 03:18:49 PM IST
+//
+
+
+package com.baeldung.springsoap.client.gen;
+
+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 anonymous complex type.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ *
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "name"
+})
+@XmlRootElement(name = "getCountryRequest")
+public class GetCountryRequest {
+
+ @XmlElement(required = true)
+ protected String name;
+
+ /**
+ * 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/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryResponse.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryResponse.java
new file mode 100644
index 0000000000..ba1ab56cf8
--- /dev/null
+++ b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryResponse.java
@@ -0,0 +1,71 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.3.0
+// See https://javaee.github.io/jaxb-v2/
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2020.04.25 at 03:18:49 PM IST
+//
+
+
+package com.baeldung.springsoap.client.gen;
+
+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 anonymous complex type.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="country" type="{http://www.baeldung.com/springsoap/gen}country"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ *
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "country"
+})
+@XmlRootElement(name = "getCountryResponse")
+public class GetCountryResponse {
+
+ @XmlElement(required = true)
+ protected Country country;
+
+ /**
+ * Gets the value of the country property.
+ *
+ * @return
+ * possible object is
+ * {@link Country }
+ *
+ */
+ public Country getCountry() {
+ return country;
+ }
+
+ /**
+ * Sets the value of the country property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Country }
+ *
+ */
+ public void setCountry(Country value) {
+ this.country = value;
+ }
+
+}
diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/ObjectFactory.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/ObjectFactory.java
new file mode 100644
index 0000000000..88b27245be
--- /dev/null
+++ b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/ObjectFactory.java
@@ -0,0 +1,63 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.3.0
+// See https://javaee.github.io/jaxb-v2/
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2020.04.25 at 03:18:49 PM IST
+//
+
+
+package com.baeldung.springsoap.client.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.springsoap.client.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.springsoap.client.gen
+ *
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link GetCountryRequest }
+ *
+ */
+ public GetCountryRequest createGetCountryRequest() {
+ return new GetCountryRequest();
+ }
+
+ /**
+ * Create an instance of {@link GetCountryResponse }
+ *
+ */
+ public GetCountryResponse createGetCountryResponse() {
+ return new GetCountryResponse();
+ }
+
+ /**
+ * Create an instance of {@link Country }
+ *
+ */
+ public Country createCountry() {
+ return new Country();
+ }
+
+}
diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/package-info.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/package-info.java
new file mode 100644
index 0000000000..eefed169a8
--- /dev/null
+++ b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/package-info.java
@@ -0,0 +1,9 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.3.0
+// See https://javaee.github.io/jaxb-v2/
+// Any modifications to this file will be lost upon recompilation of the source schema.
+// Generated on: 2020.04.25 at 03:18:49 PM IST
+//
+
+@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.baeldung.com/springsoap/gen", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
+package com.baeldung.springsoap.client.gen;
diff --git a/spring-soap/src/main/resources/countries.wsdl b/spring-soap/src/main/resources/countries.wsdl
new file mode 100644
index 0000000000..2a2eaf05bb
--- /dev/null
+++ b/spring-soap/src/main/resources/countries.wsdl
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-soap/src/test/java/com/baeldung/springsoap/client/CountryClientLiveTest.java b/spring-soap/src/test/java/com/baeldung/springsoap/client/CountryClientLiveTest.java
new file mode 100644
index 0000000000..63dbe2a5cf
--- /dev/null
+++ b/spring-soap/src/test/java/com/baeldung/springsoap/client/CountryClientLiveTest.java
@@ -0,0 +1,36 @@
+package com.baeldung.springsoap.client;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.AnnotationConfigContextLoader;
+
+import com.baeldung.springsoap.client.gen.Currency;
+import com.baeldung.springsoap.client.gen.GetCountryResponse;
+
+//Ensure that the server - com.baeldung.springsoap.Application - is running before executing this test
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = CountryClientConfig.class, loader = AnnotationConfigContextLoader.class)
+public class CountryClientLiveTest {
+
+ @Autowired
+ CountryClient client;
+
+ @Test
+ public void givenCountryService_whenCountryPoland_thenCapitalIsWarsaw() {
+ GetCountryResponse response = client.getCountry("Poland");
+ assertEquals("Warsaw", response.getCountry()
+ .getCapital());
+ }
+
+ @Test
+ public void givenCountryService_whenCountrySpain_thenCurrencyEUR() {
+ GetCountryResponse response = client.getCountry("Spain");
+ assertEquals(Currency.EUR, response.getCountry()
+ .getCurrency());
+ }
+}
diff --git a/testing-modules/mockito-2/README.md b/testing-modules/mockito-2/README.md
index 064366dfd5..6c9ddee01d 100644
--- a/testing-modules/mockito-2/README.md
+++ b/testing-modules/mockito-2/README.md
@@ -4,3 +4,4 @@
- [Lazy Verification with Mockito 2](https://www.baeldung.com/mockito-2-lazy-verification)
- [Mockito Strict Stubbing and The UnnecessaryStubbingException](https://www.baeldung.com/mockito-unnecessary-stubbing-exception)
- [Mockito and Fluent APIs](https://www.baeldung.com/mockito-fluent-apis)
+- [Mocking the ObjectMapper readValue() Method](https://www.baeldung.com/mockito-mock-jackson-read-value)
diff --git a/testing-modules/mockito-2/pom.xml b/testing-modules/mockito-2/pom.xml
index 76608a3039..340af89c82 100644
--- a/testing-modules/mockito-2/pom.xml
+++ b/testing-modules/mockito-2/pom.xml
@@ -14,8 +14,23 @@
../../
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.version}
+
+
+ org.mockito
+ mockito-junit-jupiter
+ ${mockito.version}
+ test
+
+
+
2.21.0
+ 2.10.3
diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/objectmapper/Flower.java b/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/objectmapper/Flower.java
new file mode 100644
index 0000000000..bc366a39f9
--- /dev/null
+++ b/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/objectmapper/Flower.java
@@ -0,0 +1,32 @@
+package com.baeldung.mockito.objectmapper;
+
+public class Flower {
+
+ private String name;
+ private Integer petals;
+
+ public Flower(String name, Integer petals) {
+ this.name = name;
+ this.petals = petals;
+ }
+
+ public Flower() {
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Integer getPetals() {
+ return petals;
+ }
+
+ public void setPetals(Integer petals) {
+ this.petals = petals;
+ }
+
+}
diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/objectmapper/FlowerJsonStringValidator.java b/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/objectmapper/FlowerJsonStringValidator.java
new file mode 100644
index 0000000000..91bad66e6d
--- /dev/null
+++ b/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/objectmapper/FlowerJsonStringValidator.java
@@ -0,0 +1,17 @@
+package com.baeldung.mockito.objectmapper;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class FlowerJsonStringValidator {
+ private ObjectMapper objectMapper;
+
+ public FlowerJsonStringValidator(ObjectMapper objectMapper) {
+ this.objectMapper = objectMapper;
+ }
+
+ public boolean flowerHasPetals(String jsonFlowerAsString) throws JsonProcessingException {
+ Flower flower = objectMapper.readValue(jsonFlowerAsString, Flower.class);
+ return flower.getPetals() > 0;
+ }
+}
diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/objectmapper/FlowerJsonStringValidatorUnitTest.java b/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/objectmapper/FlowerJsonStringValidatorUnitTest.java
new file mode 100644
index 0000000000..31c3f0d01d
--- /dev/null
+++ b/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/objectmapper/FlowerJsonStringValidatorUnitTest.java
@@ -0,0 +1,53 @@
+package com.baeldung.mockito.objectmapper;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class FlowerJsonStringValidatorUnitTest {
+
+ @Mock
+ private ObjectMapper objectMapper;
+
+ private FlowerJsonStringValidator flowerJsonStringValidator;
+
+ @BeforeEach
+ public void setUp() {
+ flowerJsonStringValidator = new FlowerJsonStringValidator(objectMapper);
+ }
+
+ @Test
+ public void whenCallingHasPetalsWithPetals_thenReturnsTrue() throws JsonProcessingException {
+ Flower rose = new Flower("testFlower", 100);
+
+ when(objectMapper.readValue(anyString(), eq(Flower.class))).thenReturn(rose);
+
+ assertTrue(flowerJsonStringValidator.flowerHasPetals("this can be a very long json flower"));
+
+ verify(objectMapper, times(1)).readValue(anyString(), eq(Flower.class));
+ }
+
+ @Test
+ public void whenCallingHasPetalsWithZeroPetal_thenReturnsFalse() throws JsonProcessingException {
+ Flower rose = new Flower("testFlowerWithoutPetal", 0);
+
+ when(objectMapper.readValue(anyString(), eq(Flower.class))).thenReturn(rose);
+
+ assertFalse(flowerJsonStringValidator.flowerHasPetals("this can be a very long json flower"));
+
+ verify(objectMapper, times(1)).readValue(anyString(), eq(Flower.class));
+ }
+}
diff --git a/vavr-2/README.md b/vavr-2/README.md
new file mode 100644
index 0000000000..71814a08fd
--- /dev/null
+++ b/vavr-2/README.md
@@ -0,0 +1,8 @@
+## Vavr
+
+This module contains articles about Vavr.
+
+### Relevant Articles:
+- [Introduction to Vavr’s Either](https://www.baeldung.com/vavr-either)
+- [Interoperability Between Java and Vavr](https://www.baeldung.com/java-vavr)
+- [[<-- prev]](/vavr)
diff --git a/vavr-2/pom.xml b/vavr-2/pom.xml
new file mode 100644
index 0000000000..d20dd9afef
--- /dev/null
+++ b/vavr-2/pom.xml
@@ -0,0 +1,27 @@
+
+
+
+ parent-modules
+ com.baeldung
+ 1.0.0-SNAPSHOT
+
+ 4.0.0
+
+ vavr-2
+ vavr-2
+ jar
+
+
+
+ io.vavr
+ vavr-test
+ ${vavr.version}
+
+
+
+
+ 0.9.1
+
+
\ No newline at end of file
diff --git a/vavr/src/main/java/com/baeldung/vavr/either/EitherDemo.java b/vavr-2/src/main/java/com/baeldung/vavr/either/EitherDemo.java
similarity index 100%
rename from vavr/src/main/java/com/baeldung/vavr/either/EitherDemo.java
rename to vavr-2/src/main/java/com/baeldung/vavr/either/EitherDemo.java
diff --git a/vavr/src/test/java/com/baeldung/vavr/either/EitherUnitTest.java b/vavr-2/src/test/java/com/baeldung/vavr/either/EitherUnitTest.java
similarity index 100%
rename from vavr/src/test/java/com/baeldung/vavr/either/EitherUnitTest.java
rename to vavr-2/src/test/java/com/baeldung/vavr/either/EitherUnitTest.java
diff --git a/vavr/src/test/java/com/baeldung/vavr/interoperability/CollectionsInteroperabilityUnitTest.java b/vavr-2/src/test/java/com/baeldung/vavr/interoperability/CollectionsInteroperabilityUnitTest.java
similarity index 100%
rename from vavr/src/test/java/com/baeldung/vavr/interoperability/CollectionsInteroperabilityUnitTest.java
rename to vavr-2/src/test/java/com/baeldung/vavr/interoperability/CollectionsInteroperabilityUnitTest.java
diff --git a/vavr/README.md b/vavr/README.md
index 2b8bb25356..e04e02069f 100644
--- a/vavr/README.md
+++ b/vavr/README.md
@@ -13,5 +13,4 @@ This module contains articles about Vavr.
- [Guide to Collections API in Vavr](https://www.baeldung.com/vavr-collections)
- [Collection Factory Methods for Vavr](https://www.baeldung.com/vavr-collection-factory-methods)
- [Introduction to Future in Vavr](https://www.baeldung.com/vavr-future)
-- [Introduction to Vavr’s Either](https://www.baeldung.com/vavr-either)
-- [Interoperability Between Java and Vavr](https://www.baeldung.com/java-vavr)
+- [[next -->]](/vavr-2)