diff --git a/.gitignore b/.gitignore
index 21586748b7..b981a473f6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,7 @@
.idea/
*.iml
*.iws
+out/
# Mac
.DS_Store
@@ -27,6 +28,9 @@
log/
target/
+# Gradle
+.gradle/
+
spring-openid/src/main/resources/application.properties
.recommenders/
/spring-hibernate4/nbproject/
diff --git a/azure/README.md b/azure/README.md
index c60186e1ce..ae8c443660 100644
--- a/azure/README.md
+++ b/azure/README.md
@@ -1,4 +1,4 @@
### Relevant Articles:
-- [Deploy Spring Boot App to Azure](http://www.baeldung.com/spring-boot-azure)
+- [Deploy a Spring Boot App to Azure](http://www.baeldung.com/spring-boot-azure)
diff --git a/blade/README.md b/blade/README.md
index d823de775f..1f2a00ed3f 100644
--- a/blade/README.md
+++ b/blade/README.md
@@ -1,5 +1,5 @@
### Relevant Articles:
-- [Blade - A Complete GuideBook](http://www.baeldung.com/blade)
+- [Blade – A Complete Guidebook](http://www.baeldung.com/blade)
-Run Integration Tests with `mvn integration-test`
\ No newline at end of file
+Run Integration Tests with `mvn integration-test`
diff --git a/core-groovy-2/README.md b/core-groovy-2/README.md
index 0aed5602ab..f60bdb3cbe 100644
--- a/core-groovy-2/README.md
+++ b/core-groovy-2/README.md
@@ -2,4 +2,6 @@
## Relevant articles:
+- [String Matching in Groovy](http://www.baeldung.com/)
- [Groovy def Keyword]
+
diff --git a/core-groovy-2/pom.xml b/core-groovy-2/pom.xml
index 68382e613b..69a390a3a0 100644
--- a/core-groovy-2/pom.xml
+++ b/core-groovy-2/pom.xml
@@ -96,6 +96,15 @@
+ maven-surefire-plugin
+ 2.20.1
+
+ false
+
+ **/*Test.java
+ **/*Spec.java
+
+
diff --git a/core-groovy-2/src/test/groovy/com/baeldung/strings/StringMatchingSpec.groovy b/core-groovy-2/src/test/groovy/com/baeldung/strings/StringMatchingSpec.groovy
new file mode 100644
index 0000000000..3865bc73fa
--- /dev/null
+++ b/core-groovy-2/src/test/groovy/com/baeldung/strings/StringMatchingSpec.groovy
@@ -0,0 +1,44 @@
+package com.baeldung.strings
+
+import spock.lang.Specification
+
+import java.util.regex.Pattern
+
+class StringMatchingSpec extends Specification {
+
+ def "pattern operator example"() {
+ given: "a pattern"
+ def p = ~'foo'
+
+ expect:
+ p instanceof Pattern
+
+ and: "you can use slash strings to avoid escaping of blackslash"
+ def digitPattern = ~/\d*/
+ digitPattern.matcher('4711').matches()
+ }
+
+ def "match operator example"() {
+ expect:
+ 'foobar' ==~ /.*oba.*/
+
+ and: "matching is strict"
+ !('foobar' ==~ /foo/)
+ }
+
+ def "find operator example"() {
+ when: "using the find operator"
+ def matcher = 'foo and bar, baz and buz' =~ /(\w+) and (\w+)/
+
+ then: "will find groups"
+ matcher.size() == 2
+
+ and: "can access groups using array"
+ matcher[0][0] == 'foo and bar'
+ matcher[1][2] == 'buz'
+
+ and: "you can use it as a predicate"
+ 'foobarbaz' =~ /bar/
+ }
+
+}
diff --git a/core-groovy/README.md b/core-groovy/README.md
index 606a317747..321c37be8d 100644
--- a/core-groovy/README.md
+++ b/core-groovy/README.md
@@ -8,6 +8,8 @@
- [Types of Strings in Groovy](https://www.baeldung.com/groovy-strings)
- [A Quick Guide to Iterating a Map in Groovy](https://www.baeldung.com/groovy-map-iterating)
- [An Introduction to Traits in Groovy](https://www.baeldung.com/groovy-traits)
+- [Closures in Groovy](https://www.baeldung.com/groovy-closures)
+- [Finding Elements in Collections in Groovy](https://www.baeldung.com/groovy-collections-find-elements)
- [Lists in Groovy](https://www.baeldung.com/groovy-lists)
- [Converting a String to a Date in Groovy](https://www.baeldung.com/groovy-string-to-date)
-- [Guide to I/O in Groovy](https://www.baeldung.com/groovy-io)
+- [Guide to I/O in Groovy](https://www.baeldung.com/groovy-io)
\ No newline at end of file
diff --git a/core-groovy/src/test/groovy/com/baeldung/strings/StringMatchingSpec.groovy b/core-groovy/src/test/groovy/com/baeldung/strings/StringMatchingSpec.groovy
new file mode 100644
index 0000000000..3865bc73fa
--- /dev/null
+++ b/core-groovy/src/test/groovy/com/baeldung/strings/StringMatchingSpec.groovy
@@ -0,0 +1,44 @@
+package com.baeldung.strings
+
+import spock.lang.Specification
+
+import java.util.regex.Pattern
+
+class StringMatchingSpec extends Specification {
+
+ def "pattern operator example"() {
+ given: "a pattern"
+ def p = ~'foo'
+
+ expect:
+ p instanceof Pattern
+
+ and: "you can use slash strings to avoid escaping of blackslash"
+ def digitPattern = ~/\d*/
+ digitPattern.matcher('4711').matches()
+ }
+
+ def "match operator example"() {
+ expect:
+ 'foobar' ==~ /.*oba.*/
+
+ and: "matching is strict"
+ !('foobar' ==~ /foo/)
+ }
+
+ def "find operator example"() {
+ when: "using the find operator"
+ def matcher = 'foo and bar, baz and buz' =~ /(\w+) and (\w+)/
+
+ then: "will find groups"
+ matcher.size() == 2
+
+ and: "can access groups using array"
+ matcher[0][0] == 'foo and bar'
+ matcher[1][2] == 'buz'
+
+ and: "you can use it as a predicate"
+ 'foobarbaz' =~ /bar/
+ }
+
+}
diff --git a/core-java-11/README.md b/core-java-11/README.md
index b09649f4f1..a4b0e0e59c 100644
--- a/core-java-11/README.md
+++ b/core-java-11/README.md
@@ -6,3 +6,4 @@
- [Java 11 Nest Based Access Control](https://www.baeldung.com/java-nest-based-access-control)
- [Exploring the New HTTP Client in Java 9 and 11](https://www.baeldung.com/java-9-http-client)
- [An Introduction to Epsilon GC: A No-Op Experimental Garbage Collector](https://www.baeldung.com/jvm-epsilon-gc-garbage-collector)
+- [Guide to jlink](https://www.baeldung.com/jlink)
diff --git a/core-java-8/README.md b/core-java-8/README.md
index 99182da390..d11d2debce 100644
--- a/core-java-8/README.md
+++ b/core-java-8/README.md
@@ -3,7 +3,7 @@
## Core Java 8 Cookbooks and Examples
### Relevant Articles:
-- [Java 8 Collectors](http://www.baeldung.com/java-8-collectors)
+- [Guide to Java 8’s Collectors](http://www.baeldung.com/java-8-collectors)
- [Functional Interfaces in Java 8](http://www.baeldung.com/java-8-functional-interfaces)
- [Java 8 – Powerful Comparison with Lambdas](http://www.baeldung.com/java-8-sort-lambda)
- [New Features in Java 8](http://www.baeldung.com/java-8-new-features)
diff --git a/core-java-9/README.md b/core-java-9/README.md
index 2477a38c00..8fdc3f6ee2 100644
--- a/core-java-9/README.md
+++ b/core-java-9/README.md
@@ -5,26 +5,21 @@
[Java 9 New Features](http://www.baeldung.com/new-java-9)
### Relevant Articles:
-- [Java 9 Stream API Improvements](http://www.baeldung.com/java-9-stream-api)
-- [Java 9 Convenience Factory Methods for Collections](http://www.baeldung.com/java-9-collections-factory-methods)
+
+- [Java 9 New Features](https://www.baeldung.com/new-java-9)
- [New Stream Collectors in Java 9](http://www.baeldung.com/java9-stream-collectors)
-- [Java 9 CompletableFuture API Improvements](http://www.baeldung.com/java-9-completablefuture)
-- [Introduction to Java 9 StackWalking API](http://www.baeldung.com/java-9-stackwalking-api)
- [Introduction to Project Jigsaw](http://www.baeldung.com/project-jigsaw-java-modularity)
-- [Java 9 Optional API Additions](http://www.baeldung.com/java-9-optional)
-- [Java 9 Reactive Streams](http://www.baeldung.com/java-9-reactive-streams)
-- [Java 9 java.util.Objects Additions](http://www.baeldung.com/java-9-objects-new)
-- [Java 9 Variable Handles Demistyfied](http://www.baeldung.com/java-variable-handles)
+- [Java 9 Variable Handles Demystified](http://www.baeldung.com/java-variable-handles)
- [Exploring the New HTTP Client in Java 9 and 11](http://www.baeldung.com/java-9-http-client)
- [Method Handles in Java](http://www.baeldung.com/java-method-handles)
- [Introduction to Chronicle Queue](http://www.baeldung.com/java-chronicle-queue)
-- [A Guide to Java 9 Modularity](http://www.baeldung.com/java-9-modularity)
- [Optional orElse Optional](http://www.baeldung.com/java-optional-or-else-optional)
-- [Java 9 java.lang.Module API](http://www.baeldung.com/java-9-module-api)
- [Iterate Through a Range of Dates in Java](https://www.baeldung.com/java-iterate-date-range)
- [Initialize a HashMap in Java](https://www.baeldung.com/java-initialize-hashmap)
-- [Java 9 Platform Logging API](https://www.baeldung.com/java-9-logging-api)
- [Immutable Set in Java](https://www.baeldung.com/java-immutable-set)
- [Multi-Release Jar Files](https://www.baeldung.com/java-multi-release-jar)
- [Ahead of Time Compilation (AoT)](https://www.baeldung.com/ahead-of-time-compilation)
+- [Java 9 Process API Improvements](https://www.baeldung.com/java-9-process-api)
+- [Guide to java.lang.Process API](https://www.baeldung.com/java-process-api)
+
diff --git a/core-java-collections/README.md b/core-java-collections/README.md
index 1e504ded65..43f5bfc384 100644
--- a/core-java-collections/README.md
+++ b/core-java-collections/README.md
@@ -3,7 +3,7 @@
## Core Java Collections Cookbooks and Examples
### Relevant Articles:
-- [Java - Combine Multiple Collections](http://www.baeldung.com/java-combine-multiple-collections)
+- [Java – Combine Multiple Collections](http://www.baeldung.com/java-combine-multiple-collections)
- [HashSet and TreeSet Comparison](http://www.baeldung.com/java-hashset-vs-treeset)
- [Collect a Java Stream to an Immutable Collection](http://www.baeldung.com/java-stream-immutable-collection)
- [Introduction to the Java ArrayDeque](http://www.baeldung.com/java-array-deque)
diff --git a/core-java-concurrency-advanced/README.md b/core-java-concurrency-advanced/README.md
index f48fd30c73..8e99858693 100644
--- a/core-java-concurrency-advanced/README.md
+++ b/core-java-concurrency-advanced/README.md
@@ -12,7 +12,7 @@
- [Guide to the Java Phaser](http://www.baeldung.com/java-phaser)
- [An Introduction to Atomic Variables in Java](http://www.baeldung.com/java-atomic-variables)
- [CyclicBarrier in Java](http://www.baeldung.com/java-cyclic-barrier)
-- [Guide to Volatile Keyword in Java](http://www.baeldung.com/java-volatile)
+- [Guide to the Volatile Keyword in Java](http://www.baeldung.com/java-volatile)
- [Semaphores in Java](http://www.baeldung.com/java-semaphore)
- [Daemon Threads in Java](http://www.baeldung.com/java-daemon-thread)
- [Priority-based Job Scheduling in Java](http://www.baeldung.com/java-priority-job-schedule)
@@ -20,6 +20,6 @@
- [Print Even and Odd Numbers Using 2 Threads](https://www.baeldung.com/java-even-odd-numbers-with-2-threads)
- [Java CyclicBarrier vs CountDownLatch](https://www.baeldung.com/java-cyclicbarrier-countdownlatch)
- [Guide to the Fork/Join Framework in Java](http://www.baeldung.com/java-fork-join)
-- [A Guide to ThreadLocalRandom in Java](http://www.baeldung.com/java-thread-local-random)
+- [Guide to ThreadLocalRandom in Java](http://www.baeldung.com/java-thread-local-random)
- [The Thread.join() Method in Java](http://www.baeldung.com/java-thread-join)
- [Passing Parameters to Java Threads](https://www.baeldung.com/java-thread-parameters)
diff --git a/core-java-concurrency-basic/README.md b/core-java-concurrency-basic/README.md
index 7d106095e7..6fa702fbe7 100644
--- a/core-java-concurrency-basic/README.md
+++ b/core-java-concurrency-basic/README.md
@@ -7,13 +7,13 @@
- [A Guide to the Java ExecutorService](http://www.baeldung.com/java-executor-service-tutorial)
- [Guide to java.util.concurrent.Future](http://www.baeldung.com/java-future)
- [Difference Between Wait and Sleep in Java](http://www.baeldung.com/java-wait-and-sleep)
-- [Guide to Synchronized Keyword in Java](http://www.baeldung.com/java-synchronized)
+- [Guide to the Synchronized Keyword in Java](http://www.baeldung.com/java-synchronized)
- [Overview of the java.util.concurrent](http://www.baeldung.com/java-util-concurrent)
- [Implementing a Runnable vs Extending a Thread](http://www.baeldung.com/java-runnable-vs-extending-thread)
- [How to Kill a Java Thread](http://www.baeldung.com/java-thread-stop)
-- [ExecutorService - Waiting for Threads to Finish](http://www.baeldung.com/java-executor-wait-for-threads)
+- [ExecutorService – Waiting for Threads to Finish](http://www.baeldung.com/java-executor-wait-for-threads)
- [wait and notify() Methods in Java](http://www.baeldung.com/java-wait-notify)
- [Life Cycle of a Thread in Java](http://www.baeldung.com/java-thread-lifecycle)
- [Runnable vs. Callable in Java](http://www.baeldung.com/java-runnable-callable)
-- [What is Thread-Safety and How to Achieve it](https://www.baeldung.com/java-thread-safety)
+- [What is Thread-Safety and How to Achieve it?](https://www.baeldung.com/java-thread-safety)
- [How to Start a Thread in Java](https://www.baeldung.com/java-start-thread)
diff --git a/core-java-io/README.md b/core-java-io/README.md
index 05b9165147..9ce39459dd 100644
--- a/core-java-io/README.md
+++ b/core-java-io/README.md
@@ -6,7 +6,7 @@
- [How to Read a Large File Efficiently with Java](http://www.baeldung.com/java-read-lines-large-file)
- [Java InputStream to String](http://www.baeldung.com/convert-input-stream-to-string)
- [Java – Write to File](http://www.baeldung.com/java-write-to-file)
-- [Java - Convert File to InputStream](http://www.baeldung.com/convert-file-to-input-stream)
+- [Java – Convert File to InputStream](http://www.baeldung.com/convert-file-to-input-stream)
- [Java Scanner](http://www.baeldung.com/java-scanner)
- [Java – Byte Array to Writer](http://www.baeldung.com/java-convert-byte-array-to-writer)
- [Java – Directory Size](http://www.baeldung.com/java-folder-size)
@@ -14,7 +14,7 @@
- [File Size in Java](http://www.baeldung.com/java-file-size)
- [Comparing getPath(), getAbsolutePath(), and getCanonicalPath() in Java](http://www.baeldung.com/java-path)
- [Using Java MappedByteBuffer](http://www.baeldung.com/java-mapped-byte-buffer)
-- [Copy a File with Java](http://www.baeldung.com/java-copy-file)
+- [How to Copy a File with Java](http://www.baeldung.com/java-copy-file)
- [Java – Append Data to a File](http://www.baeldung.com/java-append-to-file)
- [FileNotFoundException in Java](http://www.baeldung.com/java-filenotfound-exception)
- [How to Read a File in Java](http://www.baeldung.com/reading-file-in-java)
diff --git a/core-java-jvm/README.md b/core-java-jvm/README.md
index 529453f3c4..82067ad952 100644
--- a/core-java-jvm/README.md
+++ b/core-java-jvm/README.md
@@ -3,4 +3,4 @@
## Core Java JVM Cookbooks and Examples
### Relevant Articles:
-- [Method Inlining in the JVM](http://www.baeldung.com/method-inlining-in-the-jvm/)
+- [Method Inlining in the JVM](https://www.baeldung.com/jvm-method-inlining)
diff --git a/core-java-lambdas/pom.xml b/core-java-lambdas/pom.xml
new file mode 100644
index 0000000000..25538a3524
--- /dev/null
+++ b/core-java-lambdas/pom.xml
@@ -0,0 +1,19 @@
+
+
+ 4.0.0
+ core-java-lambdas
+ 0.1.0-SNAPSHOT
+ core-java
+ jar
+
+
+ com.baeldung
+ parent-java
+ 0.0.1-SNAPSHOT
+ ../parent-java
+
+
+
+
\ No newline at end of file
diff --git a/core-java-lambdas/src/main/java/com/baeldung/lambdas/LambdaVariables.java b/core-java-lambdas/src/main/java/com/baeldung/lambdas/LambdaVariables.java
new file mode 100644
index 0000000000..5c1201150f
--- /dev/null
+++ b/core-java-lambdas/src/main/java/com/baeldung/lambdas/LambdaVariables.java
@@ -0,0 +1,88 @@
+package com.baeldung.lambdas;
+
+import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.function.Supplier;
+import java.util.stream.IntStream;
+
+/**
+ * Class with examples about working with capturing lambdas.
+ */
+public class LambdaVariables {
+
+ private volatile boolean run = true;
+ private int start = 0;
+
+ private ExecutorService executor = Executors.newFixedThreadPool(3);
+
+ public static void main(String[] args) {
+ new LambdaVariables().localVariableMultithreading();
+ }
+
+ Supplier incrementer(int start) {
+ return () -> start; // can't modify start parameter inside the lambda
+ }
+
+ Supplier incrementer() {
+ return () -> start++;
+ }
+
+ public void localVariableMultithreading() {
+ boolean run = true;
+ executor.execute(() -> {
+ while (run) {
+ // do operation
+ }
+ });
+ // commented because it doesn't compile, it's just an example of non-final local variables in lambdas
+ // run = false;
+ }
+
+ public void instanceVariableMultithreading() {
+ executor.execute(() -> {
+ while (run) {
+ // do operation
+ }
+ });
+
+ run = false;
+ }
+
+ /**
+ * WARNING: always avoid this workaround!!
+ */
+ public void workaroundSingleThread() {
+ int[] holder = new int[] { 2 };
+ IntStream sums = IntStream
+ .of(1, 2, 3)
+ .map(val -> val + holder[0]);
+
+ holder[0] = 0;
+
+ System.out.println(sums.sum());
+ }
+
+ /**
+ * WARNING: always avoid this workaround!!
+ */
+ public void workaroundMultithreading() {
+ int[] holder = new int[] { 2 };
+ Runnable runnable = () -> System.out.println(IntStream
+ .of(1, 2, 3)
+ .map(val -> val + holder[0])
+ .sum());
+
+ new Thread(runnable).start();
+
+ // simulating some processing
+ try {
+ Thread.sleep(new Random().nextInt(3) * 1000L);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+
+ holder[0] = 0;
+ }
+
+}
diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Entry.java b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Entry.java
new file mode 100644
index 0000000000..07759ca9ba
--- /dev/null
+++ b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Entry.java
@@ -0,0 +1,38 @@
+package com.baeldung.generics;
+
+import java.io.Serializable;
+
+public class Entry {
+ private String data;
+ private int rank;
+
+ // non-generic constructor
+ public Entry(String data, int rank) {
+ this.data = data;
+ this.rank = rank;
+ }
+
+ // generic constructor
+ public Entry(E element) {
+ this.data = element.toString();
+ this.rank = element.getRank();
+ }
+
+ // getters and setters
+ public String getData() {
+ return data;
+ }
+
+ public void setData(String data) {
+ this.data = data;
+ }
+
+ public int getRank() {
+ return rank;
+ }
+
+ public void setRank(int rank) {
+ this.rank = rank;
+ }
+
+}
diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/generics/GenericEntry.java b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/GenericEntry.java
new file mode 100644
index 0000000000..27d3a44069
--- /dev/null
+++ b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/GenericEntry.java
@@ -0,0 +1,53 @@
+package com.baeldung.generics;
+
+import java.io.Serializable;
+import java.util.Optional;
+
+public class GenericEntry {
+ private T data;
+ private int rank;
+
+ // non-generic constructor
+ public GenericEntry(int rank) {
+ this.rank = rank;
+ }
+
+ // generic constructor
+ public GenericEntry(T data, int rank) {
+ this.data = data;
+ this.rank = rank;
+ }
+
+ // generic constructor with different type
+ public GenericEntry(E element) {
+ this.data = (T) element;
+ this.rank = element.getRank();
+ }
+
+ // generic constructor with different type and wild card
+ public GenericEntry(Optional extends Rankable> optional) {
+ if (optional.isPresent()) {
+ this.data = (T) optional.get();
+ this.rank = optional.get()
+ .getRank();
+ }
+ }
+
+ // getters and setters
+ public T getData() {
+ return data;
+ }
+
+ public void setData(T data) {
+ this.data = data;
+ }
+
+ public int getRank() {
+ return rank;
+ }
+
+ public void setRank(int rank) {
+ this.rank = rank;
+ }
+
+}
diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/generics/MapEntry.java b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/MapEntry.java
new file mode 100644
index 0000000000..3d626b2fa5
--- /dev/null
+++ b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/MapEntry.java
@@ -0,0 +1,34 @@
+package com.baeldung.generics;
+
+public class MapEntry {
+ private K key;
+ private V value;
+
+ public MapEntry() {
+ super();
+ }
+
+ // generic constructor with two parameters
+ public MapEntry(K key, V value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ // getters and setters
+ public K getKey() {
+ return key;
+ }
+
+ public void setKey(K key) {
+ this.key = key;
+ }
+
+ public V getValue() {
+ return value;
+ }
+
+ public void setValue(V value) {
+ this.value = value;
+ }
+
+}
diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Product.java b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Product.java
new file mode 100644
index 0000000000..bfc9f63071
--- /dev/null
+++ b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Product.java
@@ -0,0 +1,50 @@
+package com.baeldung.generics;
+
+import java.io.Serializable;
+
+public class Product implements Rankable, Serializable {
+ private String name;
+ private double price;
+ private int sales;
+
+ public Product(String name, double price) {
+ this.name = name;
+ this.price = price;
+ }
+
+ @Override
+ public int getRank() {
+ return sales;
+ }
+
+ @Override
+ public String toString() {
+ return "Product [name=" + name + ", price=" + price + ", sales=" + sales + "]";
+ }
+
+ // getters and setters
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public double getPrice() {
+ return price;
+ }
+
+ public void setPrice(double price) {
+ this.price = price;
+ }
+
+ public int getSales() {
+ return sales;
+ }
+
+ public void setSales(int sales) {
+ this.sales = sales;
+ }
+
+}
diff --git a/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Rankable.java b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Rankable.java
new file mode 100644
index 0000000000..72bda67d9d
--- /dev/null
+++ b/core-java-lang-oop-2/src/main/java/com/baeldung/generics/Rankable.java
@@ -0,0 +1,5 @@
+package com.baeldung.generics;
+
+public interface Rankable {
+ public int getRank();
+}
diff --git a/core-java-lang-oop-2/src/test/java/com/baeldung/generics/GenericConstructorUnitTest.java b/core-java-lang-oop-2/src/test/java/com/baeldung/generics/GenericConstructorUnitTest.java
new file mode 100644
index 0000000000..60907bbfd3
--- /dev/null
+++ b/core-java-lang-oop-2/src/test/java/com/baeldung/generics/GenericConstructorUnitTest.java
@@ -0,0 +1,76 @@
+package com.baeldung.generics;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.io.Serializable;
+import java.util.Optional;
+
+import org.junit.Test;
+
+public class GenericConstructorUnitTest {
+
+ @Test
+ public void givenNonGenericConstructor_whenCreateNonGenericEntry_thenOK() {
+ Entry entry = new Entry("sample", 1);
+
+ assertEquals("sample", entry.getData());
+ assertEquals(1, entry.getRank());
+ }
+
+ @Test
+ public void givenGenericConstructor_whenCreateNonGenericEntry_thenOK() {
+ Product product = new Product("milk", 2.5);
+ product.setSales(30);
+ Entry entry = new Entry(product);
+
+ assertEquals(product.toString(), entry.getData());
+ assertEquals(30, entry.getRank());
+ }
+
+ @Test
+ public void givenNonGenericConstructor_whenCreateGenericEntry_thenOK() {
+ GenericEntry entry = new GenericEntry(1);
+
+ assertNull(entry.getData());
+ assertEquals(1, entry.getRank());
+ }
+
+ @Test
+ public void givenGenericConstructor_whenCreateGenericEntry_thenOK() {
+ GenericEntry entry = new GenericEntry("sample", 1);
+
+ assertEquals("sample", entry.getData());
+ assertEquals(1, entry.getRank());
+ }
+
+ @Test
+ public void givenGenericConstructorWithDifferentType_whenCreateGenericEntry_thenOK() {
+ Product product = new Product("milk", 2.5);
+ product.setSales(30);
+ GenericEntry entry = new GenericEntry(product);
+
+ assertEquals(product, entry.getData());
+ assertEquals(30, entry.getRank());
+ }
+
+ @Test
+ public void givenGenericConstructorWithWildCard_whenCreateGenericEntry_thenOK() {
+ Product product = new Product("milk", 2.5);
+ product.setSales(30);
+ Optional optional = Optional.of(product);
+ GenericEntry entry = new GenericEntry(optional);
+
+ assertEquals(product, entry.getData());
+ assertEquals(30, entry.getRank());
+ }
+
+ @Test
+ public void givenGenericConstructor_whenCreateGenericEntryWithTwoTypes_thenOK() {
+ MapEntry entry = new MapEntry("sample", 1);
+
+ assertEquals("sample", entry.getKey());
+ assertEquals(1, entry.getValue()
+ .intValue());
+ }
+}
diff --git a/core-java-lang-oop/README.md b/core-java-lang-oop/README.md
index 970a8d44b1..c9ee9a9e94 100644
--- a/core-java-lang-oop/README.md
+++ b/core-java-lang-oop/README.md
@@ -10,7 +10,7 @@
- [How to Make a Deep Copy of an Object in Java](http://www.baeldung.com/java-deep-copy)
- [Guide to Inheritance in Java](http://www.baeldung.com/java-inheritance)
- [Object Type Casting in Java](http://www.baeldung.com/java-type-casting)
-- [The "final" Keyword in Java](http://www.baeldung.com/java-final)
+- [The “final” Keyword in Java](http://www.baeldung.com/java-final)
- [Type Erasure in Java Explained](http://www.baeldung.com/java-type-erasure)
- [Pass-By-Value as a Parameter Passing Mechanism in Java](http://www.baeldung.com/java-pass-by-value-or-pass-by-reference)
- [Variable and Method Hiding in Java](http://www.baeldung.com/java-variable-method-hiding)
diff --git a/core-java-lang/README.md b/core-java-lang/README.md
index eaedc93eed..e9169a5820 100644
--- a/core-java-lang/README.md
+++ b/core-java-lang/README.md
@@ -12,7 +12,7 @@
- [Dynamic Proxies in Java](http://www.baeldung.com/java-dynamic-proxies)
- [Java Double Brace Initialization](http://www.baeldung.com/java-double-brace-initialization)
- [Guide to the Diamond Operator in Java](http://www.baeldung.com/java-diamond-operator)
-- [Quick Example - Comparator vs Comparable in Java](http://www.baeldung.com/java-comparator-comparable)
+- [Comparator and Comparable in Java](http://www.baeldung.com/java-comparator-comparable)
- [The Java continue and break Keywords](http://www.baeldung.com/java-continue-and-break)
- [Nested Classes in Java](http://www.baeldung.com/java-nested-classes)
- [A Guide to Inner Interfaces in Java](http://www.baeldung.com/java-inner-interfaces)
diff --git a/core-java-networking/README.md b/core-java-networking/README.md
index e76f28030d..2341520df7 100644
--- a/core-java-networking/README.md
+++ b/core-java-networking/README.md
@@ -14,4 +14,5 @@
- [A Guide to Java Sockets](http://www.baeldung.com/a-guide-to-java-sockets)
- [Guide to Java URL Encoding/Decoding](http://www.baeldung.com/java-url-encoding-decoding)
- [Do a Simple HTTP Request in Java](http://www.baeldung.com/java-http-request)
-- [Difference between URL and URI](http://www.baeldung.com/java-url-vs-uri)
\ No newline at end of file
+- [Difference between URL and URI](http://www.baeldung.com/java-url-vs-uri)
+- [Read an InputStream using the Java Server Socket](https://www.baeldung.com/java-inputstream-server-socket)
diff --git a/core-java/README.md b/core-java/README.md
index cbc9251b0b..c2d1b4a06b 100644
--- a/core-java/README.md
+++ b/core-java/README.md
@@ -29,7 +29,7 @@
- [What is the serialVersionUID?](http://www.baeldung.com/java-serial-version-uid)
- [A Guide to the ResourceBundle](http://www.baeldung.com/java-resourcebundle)
- [Class Loaders in Java](http://www.baeldung.com/java-classloaders)
-- [Guide to Java Clock Class](http://www.baeldung.com/java-clock)
+- [Guide to the Java Clock Class](http://www.baeldung.com/java-clock)
- [Importance of Main Manifest Attribute in a Self-Executing JAR](http://www.baeldung.com/java-jar-executable-manifest-main-class)
- [Java Global Exception Handler](http://www.baeldung.com/java-global-exception-handler)
- [How to Get the Size of an Object in Java](http://www.baeldung.com/java-size-of-object)
diff --git a/core-kotlin-2/README.md b/core-kotlin-2/README.md
index 4ac1c2c7bb..6d0b20135d 100644
--- a/core-kotlin-2/README.md
+++ b/core-kotlin-2/README.md
@@ -2,5 +2,8 @@
- [Void Type in Kotlin](https://www.baeldung.com/kotlin-void-type)
- [How to use Kotlin Range Expressions](https://www.baeldung.com/kotlin-ranges)
+- [Creating a Kotlin Range Iterator on a Custom Object](https://www.baeldung.com/kotlin-custom-range-iterator)
+- [Kotlin Scope Functions](https://www.baeldung.com/kotlin-scope-functions)
+- [Kotlin Annotations](https://www.baeldung.com/kotlin-annotations)
- [Split a List into Parts in Kotlin](https://www.baeldung.com/kotlin-split-list-into-parts)
-- [String Comparison in Kotlin](https://www.baeldung.com/kotlin-string-comparison)
+- [String Comparison in Kotlin](https://www.baeldung.com/kotlin-string-comparison)
\ No newline at end of file
diff --git a/core-kotlin-io/.gitignore b/core-kotlin-io/.gitignore
new file mode 100644
index 0000000000..f521947850
--- /dev/null
+++ b/core-kotlin-io/.gitignore
@@ -0,0 +1,11 @@
+/bin/
+
+#ignore gradle
+.gradle/
+
+
+#ignore build and generated files
+build/
+node/
+target/
+out/
diff --git a/core-kotlin-io/README.md b/core-kotlin-io/README.md
new file mode 100644
index 0000000000..c085c0653f
--- /dev/null
+++ b/core-kotlin-io/README.md
@@ -0,0 +1,3 @@
+## Relevant articles:
+
+- [InputStream to String in Kotlin](https://www.baeldung.com/kotlin-inputstream-to-string)
diff --git a/core-kotlin-io/pom.xml b/core-kotlin-io/pom.xml
new file mode 100644
index 0000000000..2e21079d7f
--- /dev/null
+++ b/core-kotlin-io/pom.xml
@@ -0,0 +1,78 @@
+
+
+ 4.0.0
+ core-kotlin-io
+ core-kotlin-io
+ jar
+
+
+ com.baeldung
+ parent-kotlin
+ 1.0.0-SNAPSHOT
+ ../parent-kotlin
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib-jdk8
+ ${kotlin.version}
+
+
+ org.junit.platform
+ junit-platform-runner
+ ${junit.platform.version}
+ test
+
+
+ org.assertj
+ assertj-core
+ ${assertj.version}
+ test
+
+
+ org.jetbrains.kotlin
+ kotlin-test
+ ${kotlin.version}
+ test
+
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-plugin
+ ${kotlin.version}
+
+
+ compile
+ compile
+
+ compile
+
+
+
+ test-compile
+ test-compile
+
+ test-compile
+
+
+
+
+ 1.8
+
+
+
+
+
+
+ 1.2.71
+ 1.1.1
+ 5.2.0
+ 3.10.0
+
+
+
\ No newline at end of file
diff --git a/core-kotlin-io/src/main/kotlin/com/baeldung/inputstream/InputStreamExtension.kt b/core-kotlin-io/src/main/kotlin/com/baeldung/inputstream/InputStreamExtension.kt
new file mode 100644
index 0000000000..e94a2e84ee
--- /dev/null
+++ b/core-kotlin-io/src/main/kotlin/com/baeldung/inputstream/InputStreamExtension.kt
@@ -0,0 +1,18 @@
+package com.baeldung.inputstream
+
+import java.io.InputStream
+
+fun InputStream.readUpToChar(stopChar: Char): String {
+ val stringBuilder = StringBuilder()
+ var currentChar = this.read().toChar()
+ while (currentChar != stopChar) {
+ stringBuilder.append(currentChar)
+ currentChar = this.read().toChar()
+ if (this.available() <= 0) {
+ stringBuilder.append(currentChar)
+ break
+ }
+ }
+ return stringBuilder.toString()
+}
+
diff --git a/core-kotlin-io/src/test/kotlin/com/baeldung/inputstream/InputStreamToStringTest.kt b/core-kotlin-io/src/test/kotlin/com/baeldung/inputstream/InputStreamToStringTest.kt
new file mode 100644
index 0000000000..3437ddb68a
--- /dev/null
+++ b/core-kotlin-io/src/test/kotlin/com/baeldung/inputstream/InputStreamToStringTest.kt
@@ -0,0 +1,71 @@
+package com.baeldung.inputstream
+
+import kotlinx.io.core.use
+import org.junit.Test
+import java.io.BufferedReader
+import java.io.File
+import kotlin.test.assertEquals
+
+class InputStreamToStringTest {
+ private val fileName = "src/test/resources/inputstream2string.txt"
+ private val fileFullContent = "Computer programming can be a hassle\r\n" +
+ "It's like trying to take a defended castle"
+
+ @Test
+ fun whenReadFileWithBufferedReader_thenFullFileContentIsReadAsString() {
+ val file = File(fileName)
+ val inputStream = file.inputStream()
+ val content = inputStream.bufferedReader().use(BufferedReader::readText)
+ assertEquals(fileFullContent, content)
+ }
+ @Test
+ fun whenReadFileWithBufferedReaderReadText_thenFullFileContentIsReadAsString() {
+ val file = File(fileName)
+ val inputStream = file.inputStream()
+ val reader = BufferedReader(inputStream.reader())
+ var content: String
+ try {
+ content = reader.readText()
+ } finally {
+ reader.close()
+ }
+ assertEquals(fileFullContent, content)
+ }
+ @Test
+ fun whenReadFileWithBufferedReaderManually_thenFullFileContentIsReadAsString() {
+ val file = File(fileName)
+ val inputStream = file.inputStream()
+ val reader = BufferedReader(inputStream.reader())
+ val content = StringBuilder()
+ try {
+ var line = reader.readLine()
+ while (line != null) {
+ content.append(line)
+ line = reader.readLine()
+ }
+ } finally {
+ reader.close()
+ }
+ assertEquals(fileFullContent.replace("\r\n", ""), content.toString())
+
+ }
+
+ @Test
+ fun whenReadFileUpToStopChar_thenPartBeforeStopCharIsReadAsString() {
+ val file = File(fileName)
+ val inputStream = file.inputStream()
+ val content = inputStream.use { it.readUpToChar(' ') }
+ assertEquals("Computer", content)
+ }
+
+ @Test
+ fun whenReadFileWithoutContainingStopChar_thenFullFileContentIsReadAsString() {
+ val file = File(fileName)
+ val inputStream = file.inputStream()
+ val content = inputStream.use { it.readUpToChar('-') }
+ assertEquals(fileFullContent, content)
+ }
+
+
+}
+
diff --git a/core-kotlin-io/src/test/resources/inputstream2string.txt b/core-kotlin-io/src/test/resources/inputstream2string.txt
new file mode 100644
index 0000000000..40ef9fc5f3
--- /dev/null
+++ b/core-kotlin-io/src/test/resources/inputstream2string.txt
@@ -0,0 +1,2 @@
+Computer programming can be a hassle
+It's like trying to take a defended castle
\ No newline at end of file
diff --git a/core-kotlin/README.md b/core-kotlin/README.md
index 73a78eccff..3392db9171 100644
--- a/core-kotlin/README.md
+++ b/core-kotlin/README.md
@@ -1,7 +1,7 @@
## Relevant articles:
- [Introduction to the Kotlin Language](http://www.baeldung.com/kotlin)
-- [A guide to the “when{}” block in Kotlin](http://www.baeldung.com/kotlin-when)
+- [Guide to the “when{}” Block in Kotlin](http://www.baeldung.com/kotlin-when)
- [Comprehensive Guide to Null Safety in Kotlin](http://www.baeldung.com/kotlin-null-safety)
- [Kotlin Java Interoperability](http://www.baeldung.com/kotlin-java-interoperability)
- [Difference Between “==” and “===” operators in Kotlin](http://www.baeldung.com/kotlin-equality-operators)
diff --git a/couchbase/README.md b/couchbase/README.md
index 9b76609593..7a99ce4299 100644
--- a/couchbase/README.md
+++ b/couchbase/README.md
@@ -3,7 +3,7 @@
### Relevant Articles:
- [Introduction to Couchbase SDK for Java](http://www.baeldung.com/java-couchbase-sdk)
- [Using Couchbase in a Spring Application](http://www.baeldung.com/couchbase-sdk-spring)
-- [Asynchronous Batch Opereations in Couchbase](http://www.baeldung.com/async-batch-operations-in-couchbase)
+- [Asynchronous Batch Operations in Couchbase](http://www.baeldung.com/async-batch-operations-in-couchbase)
- [Querying Couchbase with MapReduce Views](http://www.baeldung.com/couchbase-query-mapreduce-view)
- [Querying Couchbase with N1QL](http://www.baeldung.com/n1ql-couchbase)
diff --git a/gson/README.md b/gson/README.md
index fec0506488..268116a2ac 100644
--- a/gson/README.md
+++ b/gson/README.md
@@ -11,6 +11,6 @@
- [Convert JSON to a Map Using Gson](https://www.baeldung.com/gson-json-to-map)
- [Working with Primitive Values in Gson](https://www.baeldung.com/java-gson-primitives)
- [Convert String to JsonObject with Gson](https://www.baeldung.com/gson-string-to-jsonobject)
-- [Mapping Multiple JSON Fields to One Java Field](https://www.baeldung.com/json-multiple-fields-single-java-field)
+- [Mapping Multiple JSON Fields to a Single Java Field](https://www.baeldung.com/json-multiple-fields-single-java-field)
- [Serializing and Deserializing a List with Gson](https://www.baeldung.com/gson-list)
diff --git a/guava-modules/guava-21/README.md b/guava-modules/guava-21/README.md
index 68c1ac4a8e..4e897325b6 100644
--- a/guava-modules/guava-21/README.md
+++ b/guava-modules/guava-21/README.md
@@ -1,4 +1,4 @@
### Relevant articles:
-- [New Stream, Comparator and Collector Functionality in Guava 21](http://www.baeldung.com/guava-21-new)
+- [New Stream, Comparator and Collector in Guava 21](http://www.baeldung.com/guava-21-new)
- [New in Guava 21 common.util.concurrent](http://www.baeldung.com/guava-21-util-concurrent)
- [Zipping Collections in Java](http://www.baeldung.com/java-collections-zip)
diff --git a/httpclient/README.md b/httpclient/README.md
index 87fb38706d..c5956068c6 100644
--- a/httpclient/README.md
+++ b/httpclient/README.md
@@ -9,7 +9,7 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [HttpClient 4 – Send Custom Cookie](http://www.baeldung.com/httpclient-4-cookies)
- [HttpClient 4 – Get the Status Code](http://www.baeldung.com/httpclient-status-code)
-- [HttpClient 4 – Cancel / Abort Request](http://www.baeldung.com/httpclient-cancel-request)
+- [HttpClient 4 – Cancel Request](http://www.baeldung.com/httpclient-cancel-request)
- [HttpClient 4 Cookbook](http://www.baeldung.com/httpclient4)
- [Unshorten URLs with HttpClient](http://www.baeldung.com/unshorten-url-httpclient)
- [HttpClient 4 – Follow Redirects for POST](http://www.baeldung.com/httpclient-redirect-on-http-post)
diff --git a/jackson/README.md b/jackson/README.md
index e9cf6f212c..eeb8f1b874 100644
--- a/jackson/README.md
+++ b/jackson/README.md
@@ -16,7 +16,7 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Jackson – Bidirectional Relationships](http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion)
- [Jackson JSON Tutorial](http://www.baeldung.com/jackson)
- [Jackson – Working with Maps and nulls](http://www.baeldung.com/jackson-map-null-values-or-null-key)
-- [Jackson – Decide What Fields Get Serialized/Deserializaed](http://www.baeldung.com/jackson-field-serializable-deserializable-or-not)
+- [Jackson – Decide What Fields Get Serialized/Deserialized](http://www.baeldung.com/jackson-field-serializable-deserializable-or-not)
- [Jackson Annotation Examples](http://www.baeldung.com/jackson-annotations)
- [Working with Tree Model Nodes in Jackson](http://www.baeldung.com/jackson-json-node-tree-model)
- [Jackson vs Gson](http://www.baeldung.com/jackson-vs-gson)
diff --git a/java-collections-maps-2/README.md b/java-collections-maps-2/README.md
new file mode 100644
index 0000000000..8bcafccfe8
--- /dev/null
+++ b/java-collections-maps-2/README.md
@@ -0,0 +1,2 @@
+## Relevant Articles:
+- [Map of Primitives in Java](https://www.baeldung.com/java-map-primitives)
diff --git a/java-dates-2/README.md b/java-dates-2/README.md
new file mode 100644
index 0000000000..a6b5c8e574
--- /dev/null
+++ b/java-dates-2/README.md
@@ -0,0 +1,2 @@
+## Relevant Articles:
+- [Converting Between LocalDate and XMLGregorianCalendar](https://www.baeldung.com/java-localdate-to-xmlgregoriancalendar)
diff --git a/java-streams/README.md b/java-streams/README.md
index e294e5aee1..0c9588c47e 100644
--- a/java-streams/README.md
+++ b/java-streams/README.md
@@ -8,7 +8,7 @@
- [Java 8 and Infinite Streams](http://www.baeldung.com/java-inifinite-streams)
- [Java 8 Stream findFirst() vs. findAny()](http://www.baeldung.com/java-stream-findfirst-vs-findany)
- [How to Get the Last Element of a Stream in Java?](http://www.baeldung.com/java-stream-last-element)
-- [”Stream has already been operated upon or closed” Exception in Java](http://www.baeldung.com/java-stream-operated-upon-or-closed-exception)
+- [“Stream has already been operated upon or closed” Exception in Java](http://www.baeldung.com/java-stream-operated-upon-or-closed-exception)
- [Iterable to Stream in Java](http://www.baeldung.com/java-iterable-to-stream)
- [How to Iterate Over a Stream With Indices](http://www.baeldung.com/java-stream-indices)
- [Primitive Type Streams in Java 8](http://www.baeldung.com/java-8-primitive-streams)
diff --git a/kotlin-libraries/README.md b/kotlin-libraries/README.md
index 5e2526e64e..94359193b6 100644
--- a/kotlin-libraries/README.md
+++ b/kotlin-libraries/README.md
@@ -10,3 +10,5 @@
- [Introduction to Arrow in Kotlin](https://www.baeldung.com/kotlin-arrow)
- [Kotlin with Ktor](https://www.baeldung.com/kotlin-ktor)
- [REST API With Kotlin and Kovert](https://www.baeldung.com/kotlin-kovert)
+- [MockK: A Mocking Library for Kotlin](https://www.baeldung.com/kotlin-mockk)
+- [Kotlin Immutable Collections](https://www.baeldung.com/kotlin-immutable-collections)
\ No newline at end of file
diff --git a/libraries-security/pom.xml b/libraries-security/pom.xml
index 9f125361ba..17d57fe203 100644
--- a/libraries-security/pom.xml
+++ b/libraries-security/pom.xml
@@ -32,6 +32,12 @@
${scribejava.version}
+
+ com.google.crypto.tink
+ tink
+ ${tink.version}
+
+
junit
junit
@@ -55,6 +61,7 @@
5.6.0
2.3.3.RELEASE
1.3.1
+ 1.2.2
1.2.2
diff --git a/libraries-security/src/test/java/com/baeldung/tink/TinkUnitTest.java b/libraries-security/src/test/java/com/baeldung/tink/TinkUnitTest.java
new file mode 100644
index 0000000000..b98c698016
--- /dev/null
+++ b/libraries-security/src/test/java/com/baeldung/tink/TinkUnitTest.java
@@ -0,0 +1,101 @@
+package com.baeldung.tink;
+
+import com.google.crypto.tink.*;
+import com.google.crypto.tink.aead.AeadConfig;
+import com.google.crypto.tink.aead.AeadFactory;
+import com.google.crypto.tink.aead.AeadKeyTemplates;
+import com.google.crypto.tink.config.TinkConfig;
+import com.google.crypto.tink.hybrid.HybridDecryptFactory;
+import com.google.crypto.tink.hybrid.HybridEncryptFactory;
+import com.google.crypto.tink.hybrid.HybridKeyTemplates;
+import com.google.crypto.tink.mac.MacFactory;
+import com.google.crypto.tink.mac.MacKeyTemplates;
+import com.google.crypto.tink.signature.PublicKeySignFactory;
+import com.google.crypto.tink.signature.PublicKeyVerifyFactory;
+import com.google.crypto.tink.signature.SignatureKeyTemplates;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.security.GeneralSecurityException;
+
+public class TinkUnitTest {
+
+ private static final String PLAINTEXT = "BAELDUNG";
+ private static final String DATA = "TINK";
+
+ @Test
+ public void givenPlaintext_whenEncryptWithAead_thenPlaintextIsEncrypted() throws GeneralSecurityException {
+
+ AeadConfig.register();
+
+ KeysetHandle keysetHandle = KeysetHandle.generateNew(
+ AeadKeyTemplates.AES256_GCM);
+
+ Aead aead = AeadFactory.getPrimitive(keysetHandle);
+
+ byte[] ciphertext = aead.encrypt(PLAINTEXT.getBytes(),
+ DATA.getBytes());
+
+ Assert.assertNotEquals(PLAINTEXT, new String(ciphertext));
+ }
+
+ @Test
+ public void givenData_whenComputeMAC_thenVerifyMAC() throws GeneralSecurityException {
+
+ TinkConfig.register();
+
+ KeysetHandle keysetHandle = KeysetHandle.generateNew(
+ MacKeyTemplates.HMAC_SHA256_128BITTAG);
+
+ Mac mac = MacFactory.getPrimitive(keysetHandle);
+
+ byte[] tag = mac.computeMac(DATA.getBytes());
+
+ mac.verifyMac(tag, DATA.getBytes());
+ }
+
+ @Test
+ public void givenData_whenSignData_thenVerifySignature() throws GeneralSecurityException {
+
+ TinkConfig.register();
+
+ KeysetHandle privateKeysetHandle = KeysetHandle.generateNew(
+ SignatureKeyTemplates.ECDSA_P256);
+
+ PublicKeySign signer = PublicKeySignFactory.getPrimitive(privateKeysetHandle);
+
+ byte[] signature = signer.sign(DATA.getBytes());
+
+ KeysetHandle publicKeysetHandle =
+ privateKeysetHandle.getPublicKeysetHandle();
+
+ PublicKeyVerify verifier = PublicKeyVerifyFactory.getPrimitive(publicKeysetHandle);
+
+ verifier.verify(signature, DATA.getBytes());
+ }
+
+ @Test
+ public void givenPlaintext_whenEncryptWithHybridEncryption_thenVerifyDecryptedIsEqual() throws GeneralSecurityException {
+
+ TinkConfig.register();
+
+ KeysetHandle privateKeysetHandle = KeysetHandle.generateNew(
+ HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256);
+
+ KeysetHandle publicKeysetHandle = privateKeysetHandle.getPublicKeysetHandle();
+
+ HybridEncrypt hybridEncrypt = HybridEncryptFactory.getPrimitive(publicKeysetHandle);
+
+ HybridDecrypt hybridDecrypt = HybridDecryptFactory.getPrimitive(privateKeysetHandle);
+
+ String contextInfo = "Tink";
+
+ byte[] ciphertext = hybridEncrypt.encrypt(PLAINTEXT.getBytes(), contextInfo.getBytes());
+
+ byte[] plaintextDecrypted = hybridDecrypt.decrypt(ciphertext, contextInfo.getBytes());
+
+ Assert.assertEquals(PLAINTEXT,new String(plaintextDecrypted));
+ }
+}
+
+
diff --git a/libraries-server/README.md b/libraries-server/README.md
index 75c12fd61a..dc6bcd0716 100644
--- a/libraries-server/README.md
+++ b/libraries-server/README.md
@@ -3,7 +3,7 @@
- [Embedded Jetty Server in Java](http://www.baeldung.com/jetty-embedded)
- [Introduction to Netty](http://www.baeldung.com/netty)
- [Exceptions in Netty](http://www.baeldung.com/netty-exception-handling)
-- [Programatically Create, Configure, and Run a Tomcat Server](http://www.baeldung.com/tomcat-programmatic-setup)
+- [Programmatically Create, Configure and Run a Tomcat Server](http://www.baeldung.com/tomcat-programmatic-setup)
- [Creating and Configuring Jetty 9 Server in Java](http://www.baeldung.com/jetty-java-programmatic)
- [Testing Netty with EmbeddedChannel](http://www.baeldung.com/testing-netty-embedded-channel)
- [MQTT Client in Java](https://www.baeldung.com/java-mqtt-client)
diff --git a/libraries/README.md b/libraries/README.md
index 57f22631f1..f6a39daef1 100644
--- a/libraries/README.md
+++ b/libraries/README.md
@@ -6,7 +6,7 @@
- [Introduction to Apache Flink with Java](http://www.baeldung.com/apache-flink)
- [Introduction to JSONassert](http://www.baeldung.com/jsonassert)
- [Intro to JaVers](http://www.baeldung.com/javers)
-- [Intro to Serenity BDD](http://www.baeldung.com/serenity-bdd)
+- [Introduction to Serenity BDD](http://www.baeldung.com/serenity-bdd)
- [Merging Streams in Java](http://www.baeldung.com/java-merge-streams)
- [Serenity BDD and Screenplay](http://www.baeldung.com/serenity-screenplay)
- [Introduction to Quartz](http://www.baeldung.com/quartz)
@@ -14,14 +14,14 @@
- [Software Transactional Memory in Java Using Multiverse](http://www.baeldung.com/java-multiverse-stm)
- [Serenity BDD with Spring and JBehave](http://www.baeldung.com/serenity-spring-jbehave)
- [Locality-Sensitive Hashing in Java Using Java-LSH](http://www.baeldung.com/locality-sensitive-hashing)
-- [Introduction to Awaitility](http://www.baeldung.com/awaitlity-testing)
+- [Introduction to Awaitlity](http://www.baeldung.com/awaitlity-testing)
- [Guide to the HyperLogLog Algorithm](http://www.baeldung.com/java-hyperloglog)
- [Introduction to Neuroph](http://www.baeldung.com/neuroph)
- [Quick Guide to RSS with Rome](http://www.baeldung.com/rome-rss)
- [Introduction to PCollections](http://www.baeldung.com/java-pcollections)
- [Introduction to Hoverfly in Java](http://www.baeldung.com/hoverfly)
- [Introduction to Eclipse Collections](http://www.baeldung.com/eclipse-collections)
-- [DistinctBy in Java Stream API](http://www.baeldung.com/java-streams-distinct-by)
+- [DistinctBy in the Java Stream API](http://www.baeldung.com/java-streams-distinct-by)
- [Introduction to NoException](http://www.baeldung.com/no-exception)
- [Introduction to Conflict-Free Replicated Data Types](http://www.baeldung.com/java-conflict-free-replicated-data-types)
- [Introduction to javax.measure](http://www.baeldung.com/javax-measure)
@@ -36,7 +36,7 @@
- [Introduction To Docx4J](http://www.baeldung.com/docx4j)
- [Introduction to StreamEx](http://www.baeldung.com/streamex)
- [Introduction to BouncyCastle with Java](http://www.baeldung.com/java-bouncy-castle)
-- [Guide to google-http-client](http://www.baeldung.com/google-http-client)
+- [A Guide to Google-Http-Client](http://www.baeldung.com/google-http-client)
- [Interact with Google Sheets from Java](http://www.baeldung.com/google-sheets-java-client)
- [A Docker Guide for Java](http://www.baeldung.com/docker-java-api)
- [Introduction To OpenCSV](http://www.baeldung.com/opencsv)
diff --git a/logging-modules/README.md b/logging-modules/README.md
index 0f12d7eb22..17405847b1 100644
--- a/logging-modules/README.md
+++ b/logging-modules/README.md
@@ -4,5 +4,4 @@
### Relevant Articles:
- [Creating a Custom Logback Appender](http://www.baeldung.com/custom-logback-appender)
-- [Get Log Output in JSON Format](http://www.baeldung.com/java-log-json-output)
- [A Guide To Logback](http://www.baeldung.com/logback)
diff --git a/logging-modules/log4j2/README.md b/logging-modules/log4j2/README.md
index 2cf6f9768f..dd326bc7a1 100644
--- a/logging-modules/log4j2/README.md
+++ b/logging-modules/log4j2/README.md
@@ -4,3 +4,4 @@
- [Log4j 2 and Lambda Expressions](http://www.baeldung.com/log4j-2-lazy-logging)
- [Programmatic Configuration with Log4j 2](http://www.baeldung.com/log4j2-programmatic-config)
- [Creating a Custom Log4j2 Appender](https://www.baeldung.com/log4j2-custom-appender)
+- [Get Log Output in JSON](http://www.baeldung.com/java-log-json-output)
diff --git a/logging-modules/logback/README.md b/logging-modules/logback/README.md
index e69de29bb2..df55492b69 100644
--- a/logging-modules/logback/README.md
+++ b/logging-modules/logback/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles:
+
+- [Get Log Output in JSON](https://www.baeldung.com/java-log-json-output)
diff --git a/patterns/README.md b/patterns/README.md
index b3ece5e52b..f627251aa4 100644
--- a/patterns/README.md
+++ b/patterns/README.md
@@ -3,3 +3,4 @@
- [Introduction to Intercepting Filter Pattern in Java](http://www.baeldung.com/intercepting-filter-pattern-in-java)
- [Introduction to the Null Object Pattern](https://www.baeldung.com/java-null-object-pattern)
- [The Dependency Inversion Principle in Java](https://www.baeldung.com/java-dependency-inversion-principle)
+- [Avoid Check for Null Statement in Java](https://www.baeldung.com/java-avoid-null-check)
diff --git a/patterns/design-patterns/README.md b/patterns/design-patterns/README.md
index c43ea48505..605fdc0d6e 100644
--- a/patterns/design-patterns/README.md
+++ b/patterns/design-patterns/README.md
@@ -19,4 +19,4 @@
- [The Command Pattern in Java](http://www.baeldung.com/java-command-pattern)
- [Java Constructors vs Static Factory Methods](https://www.baeldung.com/java-constructors-vs-static-factory-methods)
- [The Adapter Pattern in Java](https://www.baeldung.com/java-adapter-pattern)
-- [Currying in Java](https://baeldung.com/currying-in-java)
+- [Currying in Java](https://www.baeldung.com/java-currying)
diff --git a/patterns/principles/solid/README.md b/patterns/principles/solid/README.md
index e2d72ecd28..ddd2f78b7e 100644
--- a/patterns/principles/solid/README.md
+++ b/patterns/principles/solid/README.md
@@ -1,5 +1,5 @@
### Relevant Articles:
-- [A Guide to Solid Principles](https://www.baeldung.com/solid-principles)
+- [A Solid Guide to Solid Principles](https://www.baeldung.com/solid-principles)
diff --git a/persistence-modules/README.md b/persistence-modules/README.md
index 87dc9522fd..2fbaf25f2f 100644
--- a/persistence-modules/README.md
+++ b/persistence-modules/README.md
@@ -11,3 +11,5 @@
- [Pessimistic Locking in JPA](http://www.baeldung.com/jpa-pessimistic-locking)
- [Get All Data from a Table with Hibernate](https://www.baeldung.com/hibernate-select-all)
- [Spring Data with Reactive Cassandra](https://www.baeldung.com/spring-data-cassandra-reactive)
+- [Spring Data JPA – Derived Delete Methods](https://www.baeldung.com/spring-data-jpa-deleteby)
+- [Difference Between save() and saveAndFlush() in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-save-saveandflush)
diff --git a/persistence-modules/core-java-persistence/pom.xml b/persistence-modules/core-java-persistence/pom.xml
index a777eeb73f..2ad2083fec 100644
--- a/persistence-modules/core-java-persistence/pom.xml
+++ b/persistence-modules/core-java-persistence/pom.xml
@@ -6,15 +6,21 @@
0.1.0-SNAPSHOT
core-java-persistence
jar
-
+
com.baeldung
parent-java
0.0.1-SNAPSHOT
../../parent-java
-
+
+
+ org.postgresql
+ postgresql
+ ${postgresql.version}
+ test
+
org.assertj
assertj-core
@@ -52,7 +58,7 @@
${springframework.boot.spring-boot-starter.version}
-
+
core-java-persistence
@@ -62,8 +68,10 @@
-
+
+ 42.2.5.jre7
+ 8.0.15
3.10.0
1.4.197
2.4.0
@@ -72,5 +80,5 @@
1.5.8.RELEASE
4.3.4.RELEASE
-
+
\ No newline at end of file
diff --git a/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/joins/ArticleWithAuthor.java b/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/joins/ArticleWithAuthor.java
new file mode 100644
index 0000000000..5ce196ee47
--- /dev/null
+++ b/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/joins/ArticleWithAuthor.java
@@ -0,0 +1,41 @@
+package com.baeldung.jdbc.joins;
+
+class ArticleWithAuthor {
+
+ private String title;
+
+ private String authorFirstName;
+
+ private String authorLastName;
+
+ public ArticleWithAuthor(String title, String authorFirstName, String authorLastName) {
+ this.title = title;
+ this.authorFirstName = authorFirstName;
+ this.authorLastName = authorLastName;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getAuthorFirstName() {
+ return authorFirstName;
+ }
+
+ public void setAuthorFirstName(String authorFirstName) {
+ this.authorFirstName = authorFirstName;
+ }
+
+ public String getAuthorLastName() {
+ return authorLastName;
+ }
+
+ public void setAuthorLastName(String authorLastName) {
+ this.authorLastName = authorLastName;
+ }
+
+}
diff --git a/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/joins/ArticleWithAuthorDAO.java b/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/joins/ArticleWithAuthorDAO.java
new file mode 100644
index 0000000000..55f03d99ec
--- /dev/null
+++ b/persistence-modules/core-java-persistence/src/main/java/com/baeldung/jdbc/joins/ArticleWithAuthorDAO.java
@@ -0,0 +1,61 @@
+package com.baeldung.jdbc.joins;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+
+class ArticleWithAuthorDAO {
+
+ private static final String QUERY_TEMPLATE = "SELECT ARTICLE.TITLE, AUTHOR.LAST_NAME, AUTHOR.FIRST_NAME FROM ARTICLE %s AUTHOR ON AUTHOR.id=ARTICLE.AUTHOR_ID";
+ private final Connection connection;
+
+ ArticleWithAuthorDAO(Connection connection) {
+ this.connection = connection;
+ }
+
+ List articleInnerJoinAuthor() {
+ String query = String.format(QUERY_TEMPLATE, "INNER JOIN");
+ return executeQuery(query);
+ }
+
+ List articleLeftJoinAuthor() {
+ String query = String.format(QUERY_TEMPLATE, "LEFT JOIN");
+ return executeQuery(query);
+ }
+
+ List articleRightJoinAuthor() {
+ String query = String.format(QUERY_TEMPLATE, "RIGHT JOIN");
+ return executeQuery(query);
+ }
+
+ List articleFullJoinAuthor() {
+ String query = String.format(QUERY_TEMPLATE, "FULL JOIN");
+ return executeQuery(query);
+ }
+
+ private List executeQuery(String query) {
+ try (Statement statement = connection.createStatement()) {
+ ResultSet resultSet = statement.executeQuery(query);
+ return mapToList(resultSet);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ private List mapToList(ResultSet resultSet) throws SQLException {
+ List list = new ArrayList<>();
+ while (resultSet.next()) {
+ ArticleWithAuthor articleWithAuthor = new ArticleWithAuthor(
+ resultSet.getString("TITLE"),
+ resultSet.getString("FIRST_NAME"),
+ resultSet.getString("LAST_NAME")
+ );
+ list.add(articleWithAuthor);
+ }
+ return list;
+ }
+}
diff --git a/persistence-modules/core-java-persistence/src/test/java/com/baeldung/jdbc/joins/ArticleWithAuthorDAOIntegrationTest.java b/persistence-modules/core-java-persistence/src/test/java/com/baeldung/jdbc/joins/ArticleWithAuthorDAOIntegrationTest.java
new file mode 100644
index 0000000000..5c20b6bf1e
--- /dev/null
+++ b/persistence-modules/core-java-persistence/src/test/java/com/baeldung/jdbc/joins/ArticleWithAuthorDAOIntegrationTest.java
@@ -0,0 +1,89 @@
+package com.baeldung.jdbc.joins;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ArticleWithAuthorDAOIntegrationTest {
+ private Connection connection;
+
+ private ArticleWithAuthorDAO articleWithAuthorDAO;
+
+ @Before
+ public void setup() throws ClassNotFoundException, SQLException {
+ Class.forName("org.postgresql.Driver");
+ connection = DriverManager.getConnection("jdbc:postgresql://localhost:5432/myDb", "user", "pass");
+ articleWithAuthorDAO = new ArticleWithAuthorDAO(connection);
+ Statement statement = connection.createStatement();
+ String createAuthorSql = "CREATE TABLE IF NOT EXISTS AUTHOR (ID int NOT NULL PRIMARY KEY, FIRST_NAME varchar(255), LAST_NAME varchar(255));";
+ String createArticleSql = "CREATE TABLE IF NOT EXISTS ARTICLE (ID int NOT NULL PRIMARY KEY, TITLE varchar(255) NOT NULL, AUTHOR_ID int, FOREIGN KEY(AUTHOR_ID) REFERENCES AUTHOR(ID));";
+ statement.execute(createAuthorSql);
+ statement.execute(createArticleSql);
+
+ insertTestData(statement);
+ }
+
+ @Test
+ public void whenQueryWithInnerJoin_thenShouldReturnProperRows() {
+ List articleWithAuthorList = articleWithAuthorDAO.articleInnerJoinAuthor();
+
+ assertThat(articleWithAuthorList).hasSize(4);
+ assertThat(articleWithAuthorList).noneMatch(row -> row.getAuthorFirstName() == null || row.getTitle() == null);
+ }
+
+ @Test
+ public void whenQueryWithLeftJoin_thenShouldReturnProperRows() {
+ List articleWithAuthorList = articleWithAuthorDAO.articleLeftJoinAuthor();
+
+ assertThat(articleWithAuthorList).hasSize(5);
+ assertThat(articleWithAuthorList).anyMatch(row -> row.getAuthorFirstName() == null);
+ }
+
+ @Test
+ public void whenQueryWithRightJoin_thenShouldReturnProperRows() {
+ List articleWithAuthorList = articleWithAuthorDAO.articleRightJoinAuthor();
+
+ assertThat(articleWithAuthorList).hasSize(5);
+ assertThat(articleWithAuthorList).anyMatch(row -> row.getTitle() == null);
+ }
+
+ @Test
+ public void whenQueryWithFullJoin_thenShouldReturnProperRows() {
+ List articleWithAuthorList = articleWithAuthorDAO.articleFullJoinAuthor();
+
+ assertThat(articleWithAuthorList).hasSize(6);
+ assertThat(articleWithAuthorList).anyMatch(row -> row.getTitle() == null);
+ assertThat(articleWithAuthorList).anyMatch(row -> row.getAuthorFirstName() == null);
+ }
+
+ @After
+ public void cleanup() throws SQLException {
+ connection.createStatement().execute("DROP TABLE ARTICLE");
+ connection.createStatement().execute("DROP TABLE AUTHOR");
+ connection.close();
+ }
+
+ public void insertTestData(Statement statement) throws SQLException {
+ String insertAuthors = "INSERT INTO AUTHOR VALUES "
+ + "(1, 'Siena', 'Kerr'),"
+ + "(2, 'Daniele', 'Ferguson'),"
+ + "(3, 'Luciano', 'Wise'),"
+ + "(4, 'Jonas', 'Lugo');";
+ String insertArticles = "INSERT INTO ARTICLE VALUES "
+ + "(1, 'First steps in Java', 1),"
+ + "(2, 'SpringBoot tutorial', 1),"
+ + "(3, 'Java 12 insights', null),"
+ + "(4, 'SQL JOINS', 2),"
+ + "(5, 'Introduction to Spring Security', 3);";
+ statement.execute(insertAuthors);
+ statement.execute(insertArticles);
+ }
+}
diff --git a/persistence-modules/hibernate5/README.md b/persistence-modules/hibernate5/README.md
index a37720a428..68008bc8fe 100644
--- a/persistence-modules/hibernate5/README.md
+++ b/persistence-modules/hibernate5/README.md
@@ -32,3 +32,4 @@
- [Common Hibernate Exceptions](https://www.baeldung.com/hibernate-exceptions)
- [Hibernate Aggregate Functions](https://www.baeldung.com/hibernate-aggregate-functions)
- [Hibernate Query Plan Cache](https://www.baeldung.com/hibernate-query-plan-cache)
+- [TransactionRequiredException Error](https://www.baeldung.com/jpa-transaction-required-exception)
diff --git a/persistence-modules/java-jpa/README.md b/persistence-modules/java-jpa/README.md
index 2424999fb3..5be1015942 100644
--- a/persistence-modules/java-jpa/README.md
+++ b/persistence-modules/java-jpa/README.md
@@ -2,7 +2,7 @@
- [A Guide to SqlResultSetMapping](http://www.baeldung.com/jpa-sql-resultset-mapping)
- [A Guide to Stored Procedures with JPA](http://www.baeldung.com/jpa-stored-procedures)
-- [Fixing the JPA error “java.lang.String cannot be cast to Ljava.lang.String;”](https://www.baeldung.com/jpa-error-java-lang-string-cannot-be-cast)
+- [Fixing the JPA error “java.lang.String cannot be cast to [Ljava.lang.String;”]](https://www.baeldung.com/jpa-error-java-lang-string-cannot-be-cast)
- [JPA Entity Graph](https://www.baeldung.com/jpa-entity-graph)
- [JPA 2.2 Support for Java 8 Date/Time Types](https://www.baeldung.com/jpa-java-time)
- [Converting Between LocalDate and SQL Date](https://www.baeldung.com/java-convert-localdate-sql-date)
diff --git a/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/springboot/SpringBootH2Application.java b/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/springboot/SpringBootH2Application.java
new file mode 100644
index 0000000000..378093cfa9
--- /dev/null
+++ b/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/springboot/SpringBootH2Application.java
@@ -0,0 +1,12 @@
+package com.baeldung.h2db.springboot;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SpringBootH2Application {
+
+ public static void main(String... args) {
+ SpringApplication.run(SpringBootH2Application.class, args);
+ }
+}
diff --git a/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/springboot/daos/UserRepository.java b/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/springboot/daos/UserRepository.java
new file mode 100644
index 0000000000..35e496e910
--- /dev/null
+++ b/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/springboot/daos/UserRepository.java
@@ -0,0 +1,10 @@
+package com.baeldung.h2db.springboot.daos;
+
+
+
+
+import com.baeldung.h2db.springboot.models.User;
+import org.springframework.data.repository.CrudRepository;
+
+public interface UserRepository extends CrudRepository {
+}
diff --git a/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/springboot/models/User.java b/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/springboot/models/User.java
new file mode 100644
index 0000000000..fa3c01c035
--- /dev/null
+++ b/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/java/com/baeldung/h2db/springboot/models/User.java
@@ -0,0 +1,54 @@
+package com.baeldung.h2db.springboot.models;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Table(name = "users")
+@Entity
+public class User {
+
+ @Id
+ @GeneratedValue
+ private int id;
+
+ private String firstName;
+
+ private String lastName;
+
+ public User() { }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ @Override
+ public String toString() {
+ return "User{" +
+ "id=" + id +
+ ", firstName='" + firstName + '\'' +
+ ", lastName='" + lastName + '\'' +
+ '}';
+ }
+}
diff --git a/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/resources/application.properties b/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/resources/application.properties
index 5e425a3550..109b389b58 100644
--- a/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/resources/application.properties
+++ b/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/main/resources/application.properties
@@ -2,7 +2,7 @@ spring.datasource.url=jdbc:h2:mem:mydb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
-spring.jpa.hibernate.ddl-auto=create
+spring.jpa.hibernate.ddl-auto=create-drop
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
debug=true
\ No newline at end of file
diff --git a/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/test/java/com/baeldung/SpringBootH2IntegrationTest.java b/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/test/java/com/baeldung/SpringBootH2IntegrationTest.java
new file mode 100644
index 0000000000..aecc63c599
--- /dev/null
+++ b/persistence-modules/spring-boot-h2/spring-boot-h2-database/src/test/java/com/baeldung/SpringBootH2IntegrationTest.java
@@ -0,0 +1,50 @@
+package com.baeldung;
+
+import com.baeldung.h2db.springboot.SpringBootH2Application;
+import com.baeldung.h2db.springboot.daos.UserRepository;
+import com.baeldung.h2db.springboot.models.User;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.List;
+
+import static org.junit.Assert.*;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = SpringBootH2Application.class)
+public class SpringBootH2IntegrationTest {
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Test
+ public void contextLoads() { }
+
+ @Test
+ public void givenUserProfile_whenAddUser_thenCreateNewUser() {
+ User user = new User();
+ user.setFirstName("John");
+ user.setLastName("Doe");
+ userRepository.save(user);
+ List users = (List) userRepository.findAll();
+ assertFalse(users.isEmpty());
+
+ String firstName = "Aliko";
+ String lastName = "Dangote";
+ User user1 = userRepository.findById(users.get(0).getId()).get();
+ user1.setLastName(lastName);
+ user1.setFirstName(firstName);
+ userRepository.save(user1);
+
+ user = userRepository.findById(user.getId()).get();
+ assertEquals(user.getFirstName(), firstName);
+ assertEquals(user.getLastName(), lastName);
+
+ userRepository.deleteById(user.getId());
+ assertTrue( ((List) userRepository.findAll()).isEmpty());
+ }
+
+}
diff --git a/persistence-modules/spring-boot-persistence/README.MD b/persistence-modules/spring-boot-persistence/README.MD
index ee7c2e298e..709f505ea9 100644
--- a/persistence-modules/spring-boot-persistence/README.MD
+++ b/persistence-modules/spring-boot-persistence/README.MD
@@ -8,3 +8,4 @@
- [Integrating Spring Boot with HSQLDB](https://www.baeldung.com/spring-boot-hsqldb)
- [Configuring a DataSource Programmatically in Spring Boot](https://www.baeldung.com/spring-boot-configure-data-source-programmatic)
- [Resolving “Failed to Configure a DataSource” Error](https://www.baeldung.com/spring-boot-failed-to-configure-data-source)
+- [Spring Boot with Hibernate](https://www.baeldung.com/spring-boot-hibernate)
diff --git a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/config/H2JpaConfig.java b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/config/H2JpaConfig.java
index 547a905d91..c5c77be56f 100644
--- a/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/config/H2JpaConfig.java
+++ b/persistence-modules/spring-boot-persistence/src/main/java/com/baeldung/boot/config/H2JpaConfig.java
@@ -1,13 +1,9 @@
package com.baeldung.boot.config;
-import java.util.Properties;
-
-import javax.persistence.EntityManagerFactory;
-import javax.sql.DataSource;
-
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@@ -17,10 +13,17 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
+import javax.persistence.EntityManagerFactory;
+import javax.sql.DataSource;
+import java.util.Properties;
+
@Configuration
@EnableJpaRepositories(basePackages = { "com.baeldung.boot.repository", "com.baeldung.repository" })
@PropertySource("classpath:persistence-generic-entity.properties")
@EnableTransactionManagement
+@Profile("default") //only required to allow H2JpaConfig and H2TestProfileJPAConfig to coexist in same project
+ //this demo project is showcasing several ways to achieve the same end, and class-level
+ //Profile annotations are only necessary because the different techniques are sharing a project
public class H2JpaConfig {
@Autowired
diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootProfileIntegrationTest.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootProfileIntegrationTest.java
index 0227458987..d7bb44e133 100644
--- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootProfileIntegrationTest.java
+++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/SpringBootProfileIntegrationTest.java
@@ -1,8 +1,9 @@
package com.baeldung;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
+import com.baeldung.boot.Application;
+import com.baeldung.boot.domain.GenericEntity;
+import com.baeldung.boot.repository.GenericEntityRepository;
+import com.baeldung.config.H2TestProfileJPAConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@@ -10,13 +11,11 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
-import com.baeldung.boot.Application;
-import com.baeldung.boot.config.H2JpaConfig;
-import com.baeldung.boot.domain.GenericEntity;
-import com.baeldung.boot.repository.GenericEntityRepository;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
@RunWith(SpringRunner.class)
-@SpringBootTest(classes = { Application.class, H2JpaConfig.class })
+@SpringBootTest(classes = { Application.class, H2TestProfileJPAConfig.class })
@ActiveProfiles("test")
public class SpringBootProfileIntegrationTest {
@Autowired
diff --git a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/config/H2TestProfileJPAConfig.java b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/config/H2TestProfileJPAConfig.java
index e0678bcf47..f73000a10e 100644
--- a/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/config/H2TestProfileJPAConfig.java
+++ b/persistence-modules/spring-boot-persistence/src/test/java/com/baeldung/config/H2TestProfileJPAConfig.java
@@ -1,10 +1,5 @@
package com.baeldung.config;
-import java.util.Properties;
-
-import javax.persistence.EntityManagerFactory;
-import javax.sql.DataSource;
-
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -17,9 +12,16 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
+import javax.persistence.EntityManagerFactory;
+import javax.sql.DataSource;
+import java.util.Properties;
+
@Configuration
@EnableJpaRepositories(basePackages = { "com.baeldung.repository", "com.baeldung.boot.repository" })
@EnableTransactionManagement
+@Profile("test") //only required to allow H2JpaConfig and H2TestProfileJPAConfig to coexist in same project
+ //this demo project is showcasing several ways to achieve the same end, and class-level
+ //Profile annotations are only necessary because the different techniques are sharing a project
public class H2TestProfileJPAConfig {
@Autowired
diff --git a/persistence-modules/spring-data-couchbase-2/README.md b/persistence-modules/spring-data-couchbase-2/README.md
index 2b6a1faddf..3145fc653a 100644
--- a/persistence-modules/spring-data-couchbase-2/README.md
+++ b/persistence-modules/spring-data-couchbase-2/README.md
@@ -2,7 +2,7 @@
### Relevant Articles:
- [Intro to Spring Data Couchbase](http://www.baeldung.com/spring-data-couchbase)
-- [Entity Validation, Query Consistency, and Optimistic Locking in Spring Data Couchbase](http://www.baeldung.com/entity-validation-locking-and-query-consistency-in-spring-data-couchbase)
+- [Entity Validation, Optimistic Locking, and Query Consistency in Spring Data Couchbase](http://www.baeldung.com/entity-validation-locking-and-query-consistency-in-spring-data-couchbase)
- [Multiple Buckets and Spatial View Queries in Spring Data Couchbase](http://www.baeldung.com/spring-data-couchbase-buckets-and-spatial-view-queries)
### Overview
diff --git a/persistence-modules/spring-data-jpa-2/README.md b/persistence-modules/spring-data-jpa-2/README.md
index 295a434d17..41381ab82a 100644
--- a/persistence-modules/spring-data-jpa-2/README.md
+++ b/persistence-modules/spring-data-jpa-2/README.md
@@ -3,3 +3,4 @@
## Spring Data JPA Example Project
### Relevant Articles:
+- [Spring Data JPA – Derived Delete Methods](https://www.baeldung.com/spring-data-jpa-deleteby)
diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/entity/Book.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/entity/Book.java
new file mode 100644
index 0000000000..deac24548a
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/entity/Book.java
@@ -0,0 +1,51 @@
+package com.baeldung.datajpadelete.entity;
+
+import javax.persistence.*;
+
+@Entity
+public class Book {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+ private String title;
+
+ @ManyToOne
+ private Category category;
+
+ public Book() {
+ }
+
+ public Book(String title) {
+ this.title = title;
+ }
+
+ public Book(String title, Category category) {
+ this.title = title;
+ this.category = category;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public Category getCategory() {
+ return category;
+ }
+
+ public void setCategory(Category category) {
+ this.category = category;
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/entity/Category.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/entity/Category.java
new file mode 100644
index 0000000000..16f1a4157f
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/entity/Category.java
@@ -0,0 +1,60 @@
+package com.baeldung.datajpadelete.entity;
+
+import javax.persistence.*;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Entity
+public class Category {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+ private String name;
+
+ @OneToMany(mappedBy = "category", cascade = CascadeType.ALL, orphanRemoval = true)
+ private List books;
+
+ public Category() {
+ }
+
+ public Category(String name) {
+ this.name = name;
+ }
+
+ public Category(String name, Book... books) {
+ this.name = name;
+ this.books = Stream.of(books).collect(Collectors.toList());
+ this.books.forEach(x -> x.setCategory(this));
+ }
+
+ public Category(String name, List books) {
+ this.name = name;
+ this.books = books;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List getBooks() {
+ return books;
+ }
+
+ public void setBooks(List books) {
+ this.books = books;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/repository/BookRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/repository/BookRepository.java
new file mode 100644
index 0000000000..5d0f45f127
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/repository/BookRepository.java
@@ -0,0 +1,19 @@
+package com.baeldung.datajpadelete.repository;
+
+import com.baeldung.datajpadelete.entity.Book;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface BookRepository extends CrudRepository {
+
+ long deleteByTitle(String title);
+
+ @Modifying
+ @Query("delete from Book b where b.title=:title")
+ void deleteBooks(@Param("title") String title);
+
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/repository/CategoryRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/repository/CategoryRepository.java
new file mode 100644
index 0000000000..6fe7058a78
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/datajpadelete/repository/CategoryRepository.java
@@ -0,0 +1,9 @@
+package com.baeldung.datajpadelete.repository;
+
+import com.baeldung.datajpadelete.entity.Category;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface CategoryRepository extends CrudRepository {
+}
diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/model/Company.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/model/Company.java
new file mode 100644
index 0000000000..203cff1e35
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/model/Company.java
@@ -0,0 +1,71 @@
+package com.baeldung.embeddable.model;
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+@Entity
+public class Company {
+
+ @Id
+ @GeneratedValue
+ private Integer id;
+
+ private String name;
+
+ private String address;
+
+ private String phone;
+
+ @Embedded
+ @AttributeOverrides(value = {
+ @AttributeOverride( name = "firstName", column = @Column(name = "contact_first_name")),
+ @AttributeOverride( name = "lastName", column = @Column(name = "contact_last_name")),
+ @AttributeOverride( name = "phone", column = @Column(name = "contact_phone"))
+ })
+ private ContactPerson contactPerson;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public String getPhone() {
+ return phone;
+ }
+
+ public void setPhone(String phone) {
+ this.phone = phone;
+ }
+
+ public ContactPerson getContactPerson() {
+ return contactPerson;
+ }
+
+ public void setContactPerson(ContactPerson contactPerson) {
+ this.contactPerson = contactPerson;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/model/ContactPerson.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/model/ContactPerson.java
new file mode 100644
index 0000000000..561da80878
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/model/ContactPerson.java
@@ -0,0 +1,38 @@
+package com.baeldung.embeddable.model;
+
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class ContactPerson {
+
+ private String firstName;
+
+ private String lastName;
+
+ private String phone;
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public String getPhone() {
+ return phone;
+ }
+
+ public void setPhone(String phone) {
+ this.phone = phone;
+ }
+
+}
diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/repositories/CompanyRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/repositories/CompanyRepository.java
new file mode 100644
index 0000000000..f456b15652
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/embeddable/repositories/CompanyRepository.java
@@ -0,0 +1,18 @@
+package com.baeldung.embeddable.repositories;
+
+import com.baeldung.embeddable.model.Company;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.List;
+
+public interface CompanyRepository extends JpaRepository {
+
+ List findByContactPersonFirstName(String firstName);
+
+ @Query("SELECT C FROM Company C WHERE C.contactPerson.firstName = ?1")
+ List findByContactPersonFirstNameWithJPQL(String firstName);
+
+ @Query(value = "SELECT * FROM company WHERE contact_first_name = ?1", nativeQuery = true)
+ List findByContactPersonFirstNameWithNativeQuery(String firstName);
+}
diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/model/Address.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/model/Address.java
new file mode 100644
index 0000000000..0c5a3eac60
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/model/Address.java
@@ -0,0 +1,57 @@
+package com.baeldung.projection.model;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.OneToOne;
+
+@Entity
+public class Address {
+ @Id
+ private Long id;
+ @OneToOne
+ private Person person;
+ private String state;
+ private String city;
+ private String street;
+ private String zipCode;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public void setState(String state) {
+ this.state = state;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ public String getStreet() {
+ return street;
+ }
+
+ public void setStreet(String street) {
+ this.street = street;
+ }
+
+ public String getZipCode() {
+ return zipCode;
+ }
+
+ public void setZipCode(String zipCode) {
+ this.zipCode = zipCode;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/model/Person.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/model/Person.java
new file mode 100644
index 0000000000..d18bd1c72d
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/model/Person.java
@@ -0,0 +1,47 @@
+package com.baeldung.projection.model;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.OneToOne;
+
+@Entity
+public class Person {
+ @Id
+ private Long id;
+ private String firstName;
+ private String lastName;
+ @OneToOne(mappedBy = "person")
+ private Address address;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public Address getAddress() {
+ return address;
+ }
+
+ public void setAddress(Address address) {
+ this.address = address;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/repository/AddressRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/repository/AddressRepository.java
new file mode 100644
index 0000000000..c1053f4867
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/repository/AddressRepository.java
@@ -0,0 +1,11 @@
+package com.baeldung.projection.repository;
+
+import com.baeldung.projection.view.AddressView;
+import com.baeldung.projection.model.Address;
+import org.springframework.data.repository.Repository;
+
+import java.util.List;
+
+public interface AddressRepository extends Repository {
+ List getAddressByState(String state);
+}
diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/repository/PersonRepository.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/repository/PersonRepository.java
new file mode 100644
index 0000000000..64bc7471e6
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/repository/PersonRepository.java
@@ -0,0 +1,14 @@
+package com.baeldung.projection.repository;
+
+import com.baeldung.projection.model.Person;
+import com.baeldung.projection.view.PersonDto;
+import com.baeldung.projection.view.PersonView;
+import org.springframework.data.repository.Repository;
+
+public interface PersonRepository extends Repository {
+ PersonView findByLastName(String lastName);
+
+ PersonDto findByFirstName(String firstName);
+
+ T findByLastName(String lastName, Class type);
+}
diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/AddressView.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/AddressView.java
new file mode 100644
index 0000000000..7a24a1e9b9
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/AddressView.java
@@ -0,0 +1,7 @@
+package com.baeldung.projection.view;
+
+public interface AddressView {
+ String getZipCode();
+
+ PersonView getPerson();
+}
diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/PersonDto.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/PersonDto.java
new file mode 100644
index 0000000000..1fd924450b
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/PersonDto.java
@@ -0,0 +1,34 @@
+package com.baeldung.projection.view;
+
+import java.util.Objects;
+
+public class PersonDto {
+ private final String firstName;
+ private final String lastName;
+
+ public PersonDto(String firstName, String lastName) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ PersonDto personDto = (PersonDto) o;
+ return Objects.equals(firstName, personDto.firstName) && Objects.equals(lastName, personDto.lastName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(firstName, lastName);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/PersonView.java b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/PersonView.java
new file mode 100644
index 0000000000..36777ec26f
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/main/java/com/baeldung/projection/view/PersonView.java
@@ -0,0 +1,12 @@
+package com.baeldung.projection.view;
+
+import org.springframework.beans.factory.annotation.Value;
+
+public interface PersonView {
+ String getFirstName();
+
+ String getLastName();
+
+ @Value("#{target.firstName + ' ' + target.lastName}")
+ String getFullName();
+}
diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/datajpadelete/DeleteFromRepositoryUnitTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/datajpadelete/DeleteFromRepositoryUnitTest.java
new file mode 100644
index 0000000000..9e7e516735
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/datajpadelete/DeleteFromRepositoryUnitTest.java
@@ -0,0 +1,72 @@
+package com.baeldung.datajpadelete;
+
+import com.baeldung.Application;
+import com.baeldung.datajpadelete.entity.Book;
+import com.baeldung.datajpadelete.repository.BookRepository;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Arrays;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = {Application.class})
+public class DeleteFromRepositoryUnitTest {
+
+ @Autowired
+ private BookRepository repository;
+
+ Book book1;
+ Book book2;
+
+ @Before
+ public void setup() {
+ book1 = new Book("The Hobbit");
+ book2 = new Book("All Quiet on the Western Front");
+
+ repository.saveAll(Arrays.asList(book1, book2));
+ }
+
+ @After
+ public void teardown() {
+ repository.deleteAll();
+ }
+
+ @Test
+ public void whenDeleteByIdFromRepository_thenDeletingShouldBeSuccessful() {
+ repository.deleteById(book1.getId());
+
+ assertThat(repository.count() == 1).isTrue();
+ }
+
+ @Test
+ public void whenDeleteAllFromRepository_thenRepositoryShouldBeEmpty() {
+ repository.deleteAll();
+
+ assertThat(repository.count() == 0).isTrue();
+ }
+
+ @Test
+ @Transactional
+ public void whenDeleteFromDerivedQuery_thenDeletingShouldBeSuccessful() {
+ repository.deleteByTitle("The Hobbit");
+
+ assertThat(repository.count() == 1).isTrue();
+ }
+
+ @Test
+ @Transactional
+ public void whenDeleteFromCustomQuery_thenDeletingShouldBeSuccessful() {
+ repository.deleteBooks("The Hobbit");
+
+ assertThat(repository.count() == 1).isTrue();
+ }
+
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/datajpadelete/DeleteInRelationshipsUnitTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/datajpadelete/DeleteInRelationshipsUnitTest.java
new file mode 100644
index 0000000000..56de8749b2
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/datajpadelete/DeleteInRelationshipsUnitTest.java
@@ -0,0 +1,60 @@
+package com.baeldung.datajpadelete;
+
+import com.baeldung.Application;
+import com.baeldung.datajpadelete.entity.Book;
+import com.baeldung.datajpadelete.entity.Category;
+import com.baeldung.datajpadelete.repository.BookRepository;
+import com.baeldung.datajpadelete.repository.CategoryRepository;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = {Application.class})
+public class DeleteInRelationshipsUnitTest {
+
+ @Autowired
+ private BookRepository bookRepository;
+
+ @Autowired
+ private CategoryRepository categoryRepository;
+
+ @Before
+ public void setup() {
+ Book book1 = new Book("The Hobbit");
+ Category category1 = new Category("Cat1", book1);
+ categoryRepository.save(category1);
+
+ Book book2 = new Book("All Quiet on the Western Front");
+ Category category2 = new Category("Cat2", book2);
+ categoryRepository.save(category2);
+ }
+
+ @After
+ public void teardown() {
+ bookRepository.deleteAll();
+ categoryRepository.deleteAll();
+ }
+
+ @Test
+ public void whenDeletingCategories_thenBooksShouldAlsoBeDeleted() {
+ categoryRepository.deleteAll();
+
+ assertThat(bookRepository.count() == 0).isTrue();
+ assertThat(categoryRepository.count() == 0).isTrue();
+ }
+
+ @Test
+ public void whenDeletingBooks_thenCategoriesShouldAlsoBeDeleted() {
+ bookRepository.deleteAll();
+
+ assertThat(bookRepository.count() == 0).isTrue();
+ assertThat(categoryRepository.count() == 2).isTrue();
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/embeddable/EmbeddableIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/embeddable/EmbeddableIntegrationTest.java
new file mode 100644
index 0000000000..b4c365a2d9
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/embeddable/EmbeddableIntegrationTest.java
@@ -0,0 +1,125 @@
+package com.baeldung.embeddable;
+
+import com.baeldung.Application;
+import com.baeldung.embeddable.model.Company;
+import com.baeldung.embeddable.model.ContactPerson;
+import com.baeldung.embeddable.repositories.CompanyRepository;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = {Application.class})
+public class EmbeddableIntegrationTest {
+
+ @Autowired
+ private CompanyRepository companyRepository;
+
+ @Test
+ @Transactional
+ public void whenInsertingCompany_thenEmbeddedContactPersonDetailsAreMapped() {
+ ContactPerson contactPerson = new ContactPerson();
+ contactPerson.setFirstName("First");
+ contactPerson.setLastName("Last");
+ contactPerson.setPhone("123-456-789");
+
+ Company company = new Company();
+ company.setName("Company");
+ company.setAddress("1st street");
+ company.setPhone("987-654-321");
+ company.setContactPerson(contactPerson);
+
+ companyRepository.save(company);
+
+ Company result = companyRepository.getOne(company.getId());
+
+ assertEquals("Company", result.getName());
+ assertEquals("1st street", result.getAddress());
+ assertEquals("987-654-321", result.getPhone());
+ assertEquals("First", result.getContactPerson().getFirstName());
+ assertEquals("Last", result.getContactPerson().getLastName());
+ assertEquals("123-456-789", result.getContactPerson().getPhone());
+ }
+
+ @Test
+ @Transactional
+ public void whenFindingCompanyByContactPersonAttribute_thenCompanyIsReturnedProperly() {
+ ContactPerson contactPerson = new ContactPerson();
+ contactPerson.setFirstName("Name");
+ contactPerson.setLastName("Last");
+ contactPerson.setPhone("123-456-789");
+
+ Company company = new Company();
+ company.setName("Company");
+ company.setAddress("1st street");
+ company.setPhone("987-654-321");
+ company.setContactPerson(contactPerson);
+
+ companyRepository.save(company);
+
+ List result = companyRepository.findByContactPersonFirstName("Name");
+
+ assertEquals(1, result.size());
+
+ result = companyRepository.findByContactPersonFirstName("FirstName");
+
+ assertEquals(0, result.size());
+ }
+
+ @Test
+ @Transactional
+ public void whenFindingCompanyByContactPersonAttributeWithJPQL_thenCompanyIsReturnedProperly() {
+ ContactPerson contactPerson = new ContactPerson();
+ contactPerson.setFirstName("@QueryName");
+ contactPerson.setLastName("Last");
+ contactPerson.setPhone("123-456-789");
+
+ Company company = new Company();
+ company.setName("Company");
+ company.setAddress("1st street");
+ company.setPhone("987-654-321");
+ company.setContactPerson(contactPerson);
+
+ companyRepository.save(company);
+
+ List result = companyRepository.findByContactPersonFirstNameWithJPQL("@QueryName");
+
+ assertEquals(1, result.size());
+
+ result = companyRepository.findByContactPersonFirstNameWithJPQL("FirstName");
+
+ assertEquals(0, result.size());
+ }
+
+ @Test
+ @Transactional
+ public void whenFindingCompanyByContactPersonAttributeWithNativeQuery_thenCompanyIsReturnedProperly() {
+ ContactPerson contactPerson = new ContactPerson();
+ contactPerson.setFirstName("NativeQueryName");
+ contactPerson.setLastName("Last");
+ contactPerson.setPhone("123-456-789");
+
+ Company company = new Company();
+ company.setName("Company");
+ company.setAddress("1st street");
+ company.setPhone("987-654-321");
+ company.setContactPerson(contactPerson);
+
+ companyRepository.save(company);
+
+ List result = companyRepository.findByContactPersonFirstNameWithNativeQuery("NativeQueryName");
+
+ assertEquals(1, result.size());
+
+ result = companyRepository.findByContactPersonFirstNameWithNativeQuery("FirstName");
+
+ assertEquals(0, result.size());
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/joins/JpaJoinsIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/joins/JpaJoinsIntegrationTest.java
index d807da9845..9b0d23f3e4 100644
--- a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/joins/JpaJoinsIntegrationTest.java
+++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/joins/JpaJoinsIntegrationTest.java
@@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import com.baeldung.joins.model.Department;
import com.baeldung.joins.model.Phone;
+import java.util.Collection;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@@ -79,11 +80,11 @@ public class JpaJoinsIntegrationTest {
@Test
public void whenCollectionValuedAssociationIsJoined_ThenCanSelect() {
- TypedQuery query = entityManager.createQuery("SELECT ph FROM Employee e JOIN e.phones ph ", Phone.class);
+ TypedQuery query = entityManager.createQuery("SELECT ph FROM Employee e JOIN e.phones ph WHERE ph LIKE '1%'", Phone.class);
List resultList = query.getResultList();
- assertThat(resultList).hasSize(3);
+ assertThat(resultList).hasSize(1);
}
@Test
@@ -122,9 +123,20 @@ public class JpaJoinsIntegrationTest {
@Test
public void whenLeftAndFetchKeywordsAreSpecified_ThenCreatesOuterFetchJoin() {
TypedQuery query = entityManager.createQuery("SELECT d FROM Department d LEFT JOIN FETCH d.employees", Department.class);
+
List resultList = query.getResultList();
+
assertThat(resultList).hasSize(4);
assertThat(resultList).extracting("name")
.containsOnly("Infra", "Accounting", "Accounting", "Management");
}
+
+ @Test
+ public void whenCollectionValuedAssociationIsSpecifiedInSelect_ThenReturnsCollections() {
+ TypedQuery query = entityManager.createQuery("SELECT e.phones FROM Employee e", Collection.class);
+
+ List resultList = query.getResultList();
+
+ assertThat(resultList).extracting("number").containsOnly("111", "222", "333");
+ }
}
diff --git a/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/projection/JpaProjectionIntegrationTest.java b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/projection/JpaProjectionIntegrationTest.java
new file mode 100644
index 0000000000..96eaf4ed07
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/test/java/com/baeldung/projection/JpaProjectionIntegrationTest.java
@@ -0,0 +1,63 @@
+package com.baeldung.projection;
+
+import com.baeldung.projection.model.Person;
+import com.baeldung.projection.repository.AddressRepository;
+import com.baeldung.projection.repository.PersonRepository;
+import com.baeldung.projection.view.AddressView;
+import com.baeldung.projection.view.PersonDto;
+import com.baeldung.projection.view.PersonView;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.AFTER_TEST_METHOD;
+
+@DataJpaTest
+@RunWith(SpringRunner.class)
+@Sql(scripts = "/projection-insert-data.sql")
+@Sql(scripts = "/projection-clean-up-data.sql", executionPhase = AFTER_TEST_METHOD)
+public class JpaProjectionIntegrationTest {
+ @Autowired
+ private AddressRepository addressRepository;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @Test
+ public void whenUsingClosedProjections_thenViewWithRequiredPropertiesIsReturned() {
+ AddressView addressView = addressRepository.getAddressByState("CA").get(0);
+ assertThat(addressView.getZipCode()).isEqualTo("90001");
+
+ PersonView personView = addressView.getPerson();
+ assertThat(personView.getFirstName()).isEqualTo("John");
+ assertThat(personView.getLastName()).isEqualTo("Doe");
+ }
+
+ @Test
+ public void whenUsingOpenProjections_thenViewWithRequiredPropertiesIsReturned() {
+ PersonView personView = personRepository.findByLastName("Doe");
+ assertThat(personView.getFullName()).isEqualTo("John Doe");
+ }
+
+ @Test
+ public void whenUsingClassBasedProjections_thenDtoWithRequiredPropertiesIsReturned() {
+ PersonDto personDto = personRepository.findByFirstName("John");
+ assertThat(personDto.getFirstName()).isEqualTo("John");
+ assertThat(personDto.getLastName()).isEqualTo("Doe");
+ }
+
+ @Test
+ public void whenUsingDynamicProjections_thenObjectWithRequiredPropertiesIsReturned() {
+ Person person = personRepository.findByLastName("Doe", Person.class);
+ PersonView personView = personRepository.findByLastName("Doe", PersonView.class);
+ PersonDto personDto = personRepository.findByLastName("Doe", PersonDto.class);
+
+ assertThat(person.getFirstName()).isEqualTo("John");
+ assertThat(personView.getFirstName()).isEqualTo("John");
+ assertThat(personDto.getFirstName()).isEqualTo("John");
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-2/src/test/resources/projection-clean-up-data.sql b/persistence-modules/spring-data-jpa-2/src/test/resources/projection-clean-up-data.sql
new file mode 100644
index 0000000000..d34f6f0636
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/test/resources/projection-clean-up-data.sql
@@ -0,0 +1,2 @@
+DELETE FROM address;
+DELETE FROM person;
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-2/src/test/resources/projection-insert-data.sql b/persistence-modules/spring-data-jpa-2/src/test/resources/projection-insert-data.sql
new file mode 100644
index 0000000000..544dcc4b88
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-2/src/test/resources/projection-insert-data.sql
@@ -0,0 +1,2 @@
+INSERT INTO person(id,first_name,last_name) VALUES (1,'John','Doe');
+INSERT INTO address(id,person_id,state,city,street,zip_code) VALUES (1,1,'CA', 'Los Angeles', 'Standford Ave', '90001');
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa/README.md b/persistence-modules/spring-data-jpa/README.md
index 48c3180262..4e390c2faf 100644
--- a/persistence-modules/spring-data-jpa/README.md
+++ b/persistence-modules/spring-data-jpa/README.md
@@ -5,7 +5,7 @@
### Relevant Articles:
- [Spring JPA – Multiple Databases](http://www.baeldung.com/spring-data-jpa-multiple-databases)
- [Spring Data JPA – Adding a Method in All Repositories](http://www.baeldung.com/spring-data-jpa-method-in-all-repositories)
-- [Advanced Tagging Implementation with JPA](http://www.baeldung.com/jpa-tagging-advanced)
+- [An Advanced Tagging Implementation with JPA](http://www.baeldung.com/jpa-tagging-advanced)
- [Spring Data JPA @Query](http://www.baeldung.com/spring-data-jpa-query)
- [Spring Data Annotations](http://www.baeldung.com/spring-data-annotations)
- [Spring Data Java 8 Support](http://www.baeldung.com/spring-data-java-8)
diff --git a/pom.xml b/pom.xml
index 8746f8492b..32ac909cf7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -382,6 +382,7 @@
core-java-8
core-java-8-2
+ core-java-lambdas
core-java-arrays
@@ -540,7 +541,8 @@
software-security/sql-injection-samples
tensorflow-java
-
+ spring-boot-flowable
+
@@ -586,6 +588,7 @@
spring-5
spring-5-webflux
+ spring-5-data-reactive
spring-5-mvc
spring-5-reactive
spring-5-reactive-client
@@ -598,6 +601,7 @@
spring-akka
spring-all
spring-amqp
+ spring-amqp-simple
spring-aop
spring-apache-camel
spring-batch
@@ -764,6 +768,7 @@
xstream
tensorflow-java
+ spring-boot-flowable
@@ -906,6 +911,8 @@
persistence-modules/spring-data-eclipselink
persistence-modules/spring-data-solr
persistence-modules/spring-hibernate-5
+
+ spring-boot-flowable
@@ -947,6 +954,7 @@
core-java-concurrency-advanced
core-kotlin
core-kotlin-2
+ core-kotlin-io
jenkins/hello-world
jws
@@ -958,9 +966,6 @@
persistence-modules/java-mongodb
persistence-modules/jnosql
- spring-5-data-reactive
- spring-amqp-simple
-
vaadin
@@ -1232,6 +1237,7 @@
spring-4
spring-5
+ spring-5-data-reactive
spring-5-mvc
spring-5-reactive
spring-5-reactive-client
@@ -1244,6 +1250,7 @@
spring-akka
spring-all
spring-amqp
+ spring-amqp-simple
spring-aop
spring-apache-camel
spring-batch
@@ -1456,9 +1463,6 @@
persistence-modules/java-mongodb
persistence-modules/jnosql
- spring-5-data-reactive
- spring-amqp-simple
-
vaadin
diff --git a/rxjava-2/README.md b/rxjava-2/README.md
index d0bdeec684..4182f3fa00 100644
--- a/rxjava-2/README.md
+++ b/rxjava-2/README.md
@@ -2,8 +2,8 @@
- [RxJava and Error Handling](http://www.baeldung.com/rxjava-error-handling)
- [RxJava 2 – Flowable](http://www.baeldung.com/rxjava-2-flowable)
-- [RxJava 2 - Completable](http://www.baeldung.com/rxjava-completable)
- [RxJava Maybe](http://www.baeldung.com/rxjava-maybe)
- [Introduction to RxRelay for RxJava](http://www.baeldung.com/rx-relay)
- [Combining RxJava Completables](https://www.baeldung.com/rxjava-completable)
- [Converting Synchronous and Asynchronous APIs to Observables using RxJava2](https://www.baeldung.com/rxjava-apis-to-observables)
+- [RxJava Hooks](https://www.baeldung.com/rxjava-hooks)
diff --git a/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountCrudRepositoryIntegrationTest.java b/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountCrudRepositoryManualTest.java
similarity index 97%
rename from spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountCrudRepositoryIntegrationTest.java
rename to spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountCrudRepositoryManualTest.java
index f425826dce..d4b1d0eeda 100644
--- a/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountCrudRepositoryIntegrationTest.java
+++ b/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountCrudRepositoryManualTest.java
@@ -17,7 +17,7 @@ import static org.junit.Assert.assertNotNull;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Spring5ReactiveApplication.class)
-public class AccountCrudRepositoryIntegrationTest {
+public class AccountCrudRepositoryManualTest {
@Autowired
AccountCrudRepository repository;
diff --git a/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountMongoRepositoryIntegrationTest.java b/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountMongoRepositoryManualTest.java
similarity index 97%
rename from spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountMongoRepositoryIntegrationTest.java
rename to spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountMongoRepositoryManualTest.java
index bfa6a789b2..2ca075aa5e 100644
--- a/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountMongoRepositoryIntegrationTest.java
+++ b/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountMongoRepositoryManualTest.java
@@ -19,7 +19,7 @@ import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatc
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Spring5ReactiveApplication.class)
-public class AccountMongoRepositoryIntegrationTest {
+public class AccountMongoRepositoryManualTest {
@Autowired
AccountMongoRepository repository;
diff --git a/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountRxJavaRepositoryIntegrationTest.java b/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountRxJavaRepositoryManualTest.java
similarity index 97%
rename from spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountRxJavaRepositoryIntegrationTest.java
rename to spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountRxJavaRepositoryManualTest.java
index e9b3eb1c40..d91acd24e2 100644
--- a/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountRxJavaRepositoryIntegrationTest.java
+++ b/spring-5-data-reactive/src/test/java/com/baeldung/reactive/repository/AccountRxJavaRepositoryManualTest.java
@@ -15,7 +15,7 @@ import static org.junit.Assert.assertNotNull;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Spring5ReactiveApplication.class)
-public class AccountRxJavaRepositoryIntegrationTest {
+public class AccountRxJavaRepositoryManualTest {
@Autowired
AccountRxJavaRepository repository;
diff --git a/spring-5-data-reactive/src/test/java/com/baeldung/reactive/template/AccountTemplateOperationsIntegrationTest.java b/spring-5-data-reactive/src/test/java/com/baeldung/reactive/template/AccountTemplateOperationsManualTest.java
similarity index 97%
rename from spring-5-data-reactive/src/test/java/com/baeldung/reactive/template/AccountTemplateOperationsIntegrationTest.java
rename to spring-5-data-reactive/src/test/java/com/baeldung/reactive/template/AccountTemplateOperationsManualTest.java
index 373da0e393..5fa0e39317 100644
--- a/spring-5-data-reactive/src/test/java/com/baeldung/reactive/template/AccountTemplateOperationsIntegrationTest.java
+++ b/spring-5-data-reactive/src/test/java/com/baeldung/reactive/template/AccountTemplateOperationsManualTest.java
@@ -16,7 +16,7 @@ import static org.junit.jupiter.api.Assertions.*;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Spring5ReactiveApplication.class)
-public class AccountTemplateOperationsIntegrationTest {
+public class AccountTemplateOperationsManualTest {
@Autowired
AccountTemplateOperations accountTemplate;
diff --git a/spring-5-security-oauth/README.md b/spring-5-security-oauth/README.md
index 5a444d4784..a5cec370c7 100644
--- a/spring-5-security-oauth/README.md
+++ b/spring-5-security-oauth/README.md
@@ -1,5 +1,5 @@
## Relevant articles:
-- [Spring Security 5 -OAuth2 Login](http://www.baeldung.com/spring-security-5-oauth2-login)
+- [Spring Security 5 – OAuth2 Login](http://www.baeldung.com/spring-security-5-oauth2-login)
- [Extracting Principal and Authorities using Spring Security OAuth](https://www.baeldung.com/spring-security-oauth-principal-authorities-extractor)
- [Customizing Authorization and Token Requests with Spring Security 5.1 Client](https://www.baeldung.com/spring-security-custom-oauth-requests)
diff --git a/spring-5-webflux/README.md b/spring-5-webflux/README.md
new file mode 100644
index 0000000000..84c3d5a4ca
--- /dev/null
+++ b/spring-5-webflux/README.md
@@ -0,0 +1,4 @@
+## Relevant articles:
+
+- [Spring Boot Reactor Netty Configuration](https://www.baeldung.com/spring-boot-reactor-netty)
+- [How to Return 404 with Spring WebFlux](https://www.baeldung.com/spring-webflux-404)
diff --git a/spring-all/README.md b/spring-all/README.md
index a111d2e542..b0805e5477 100644
--- a/spring-all/README.md
+++ b/spring-all/README.md
@@ -14,7 +14,7 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Properties with Spring and Spring Boot](http://www.baeldung.com/properties-with-spring) - checkout the `org.baeldung.properties` package for all scenarios of properties injection and usage
- [Spring Profiles](http://www.baeldung.com/spring-profiles)
- [A Spring Custom Annotation for a Better DAO](http://www.baeldung.com/spring-annotation-bean-pre-processor)
-- [What's New in Spring 4.3?](http://www.baeldung.com/whats-new-in-spring-4-3)
+- [What’s New in Spring 4.3?](http://www.baeldung.com/whats-new-in-spring-4-3)
- [Running Setup Data on Startup in Spring](http://www.baeldung.com/running-setup-logic-on-startup-in-spring)
- [Quick Guide to Spring Controllers](http://www.baeldung.com/spring-controllers)
- [Quick Guide to Spring Bean Scopes](http://www.baeldung.com/spring-bean-scopes)
@@ -34,3 +34,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Spring Events](https://www.baeldung.com/spring-events)
- [Spring Null-Safety Annotations](https://www.baeldung.com/spring-null-safety-annotations)
- [Spring JDBC](https://www.baeldung.com/spring-jdbc-jdbctemplate)
+- [Using @Autowired in Abstract Classes](https://www.baeldung.com/spring-autowired-abstract-class)
diff --git a/spring-batch/README.md b/spring-batch/README.md
index 737e7e13f5..ddd830cd47 100644
--- a/spring-batch/README.md
+++ b/spring-batch/README.md
@@ -6,5 +6,5 @@
### Relevant Articles:
- [Introduction to Spring Batch](http://www.baeldung.com/introduction-to-spring-batch)
- [Spring Batch using Partitioner](http://www.baeldung.com/spring-batch-partitioner)
-- [Spring Batch Tasklets vs Chunks Approach](http://www.baeldung.com/spring-batch-tasklet-chunk)
+- [Spring Batch – Tasklets vs Chunks](http://www.baeldung.com/spring-batch-tasklet-chunk)
- [How to Trigger and Stop a Scheduled Spring Batch Job](http://www.baeldung.com/spring-batch-start-stop-job)
diff --git a/spring-boot-data/README.md b/spring-boot-data/README.md
index 21f7303c48..d93b8c3e93 100644
--- a/spring-boot-data/README.md
+++ b/spring-boot-data/README.md
@@ -1,2 +1,2 @@
### Relevant Articles:
-- [Formatting JSON Dates in Spring ](https://www.baeldung.com/spring-boot-formatting-json-dates)
\ No newline at end of file
+- [Formatting JSON Dates in Spring Boot](https://www.baeldung.com/spring-boot-formatting-json-dates)
diff --git a/spring-boot-flowable/README.md b/spring-boot-flowable/README.md
new file mode 100644
index 0000000000..8fb90d953b
--- /dev/null
+++ b/spring-boot-flowable/README.md
@@ -0,0 +1,3 @@
+### Relevant articles
+
+- [Introduction to Flowable](http://www.baeldung.com/flowable)
diff --git a/spring-boot-flowable/pom.xml b/spring-boot-flowable/pom.xml
new file mode 100644
index 0000000000..f9531a1e6a
--- /dev/null
+++ b/spring-boot-flowable/pom.xml
@@ -0,0 +1,58 @@
+
+
+ 4.0.0
+ spring-boot-flowable
+ war
+ spring-boot-flowable
+ Spring Boot Flowable Module
+
+ parent-boot-2
+ com.baeldung
+ 0.0.1-SNAPSHOT
+ ../parent-boot-2
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ com.h2database
+ h2
+ runtime
+
+
+ org.flowable
+ flowable-spring-boot-starter-rest
+ ${flowable.version}
+
+
+ org.flowable
+ flowable-spring-boot-starter-actuator
+ ${flowable.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+ 6.4.1
+
+
\ No newline at end of file
diff --git a/spring-boot-flowable/src/main/java/com/baeldung/Application.java b/spring-boot-flowable/src/main/java/com/baeldung/Application.java
new file mode 100644
index 0000000000..37dbe7dab8
--- /dev/null
+++ b/spring-boot-flowable/src/main/java/com/baeldung/Application.java
@@ -0,0 +1,13 @@
+package com.baeldung;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+}
diff --git a/spring-boot-flowable/src/main/java/com/baeldung/controller/ArticleWorkflowController.java b/spring-boot-flowable/src/main/java/com/baeldung/controller/ArticleWorkflowController.java
new file mode 100644
index 0000000000..3087d30af4
--- /dev/null
+++ b/spring-boot-flowable/src/main/java/com/baeldung/controller/ArticleWorkflowController.java
@@ -0,0 +1,32 @@
+package com.baeldung.controller;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.domain.Approval;
+import com.baeldung.domain.Article;
+import com.baeldung.service.ArticleWorkflowService;
+
+@RestController
+public class ArticleWorkflowController {
+ @Autowired
+ private ArticleWorkflowService service;
+ @PostMapping("/submit")
+ public void submit(@RequestBody Article article) {
+ service.startProcess(article);
+ }
+ @GetMapping("/tasks")
+ public List getTasks(@RequestParam String assignee) {
+ return service.getTasks(assignee);
+ }
+ @PostMapping("/review")
+ public void review(@RequestBody Approval approval) {
+ service.submitReview(approval);
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-flowable/src/main/java/com/baeldung/domain/Approval.java b/spring-boot-flowable/src/main/java/com/baeldung/domain/Approval.java
new file mode 100644
index 0000000000..b0c9c99437
--- /dev/null
+++ b/spring-boot-flowable/src/main/java/com/baeldung/domain/Approval.java
@@ -0,0 +1,24 @@
+package com.baeldung.domain;
+
+public class Approval {
+
+ private String id;
+ private boolean status;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public boolean isStatus() {
+ return status;
+ }
+
+ public void setStatus(boolean status) {
+ this.status = status;
+ }
+
+}
diff --git a/spring-boot-flowable/src/main/java/com/baeldung/domain/Article.java b/spring-boot-flowable/src/main/java/com/baeldung/domain/Article.java
new file mode 100644
index 0000000000..efa2eb431e
--- /dev/null
+++ b/spring-boot-flowable/src/main/java/com/baeldung/domain/Article.java
@@ -0,0 +1,52 @@
+package com.baeldung.domain;
+
+public class Article {
+
+ private String id;
+ private String author;
+ private String url;
+
+ public Article() {
+ }
+
+ public Article(String author, String url) {
+ this.author = author;
+ this.url = url;
+ }
+
+ public Article(String id, String author, String url) {
+ this.id = id;
+ this.author = author;
+ this.url = url;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ @Override
+ public String toString() {
+ return ("[" + this.author + " " + this.url + "]");
+ }
+
+}
diff --git a/spring-boot-flowable/src/main/java/com/baeldung/service/ArticleWorkflowService.java b/spring-boot-flowable/src/main/java/com/baeldung/service/ArticleWorkflowService.java
new file mode 100644
index 0000000000..b1e2a92354
--- /dev/null
+++ b/spring-boot-flowable/src/main/java/com/baeldung/service/ArticleWorkflowService.java
@@ -0,0 +1,55 @@
+package com.baeldung.service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.TaskService;
+import org.flowable.task.api.Task;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baeldung.domain.Approval;
+import com.baeldung.domain.Article;
+
+@Service
+public class ArticleWorkflowService {
+ @Autowired
+ private RuntimeService runtimeService;
+ @Autowired
+ private TaskService taskService;
+
+ @Transactional
+ public void startProcess(Article article) {
+ Map variables = new HashMap();
+ variables.put("author", article.getAuthor());
+ variables.put("url", article.getUrl());
+ runtimeService.startProcessInstanceByKey("articleReview", variables);
+ }
+
+ @Transactional
+ public List getTasks(String assignee) {
+ List tasks = taskService.createTaskQuery()
+ .taskCandidateGroup(assignee)
+ .list();
+
+ List articles = tasks.stream()
+ .map(task -> {
+ Map variables = taskService.getVariables(task.getId());
+ return new Article(
+ task.getId(), (String) variables.get("author"), (String) variables.get("url"));
+ })
+ .collect(Collectors.toList());
+ return articles;
+ }
+
+ @Transactional
+ public void submitReview(Approval approval) {
+ Map variables = new HashMap();
+ variables.put("approved", approval.isStatus());
+ taskService.complete(approval.getId(), variables);
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-flowable/src/main/java/com/baeldung/service/PublishArticleService.java b/spring-boot-flowable/src/main/java/com/baeldung/service/PublishArticleService.java
new file mode 100644
index 0000000000..b43f1dccdb
--- /dev/null
+++ b/spring-boot-flowable/src/main/java/com/baeldung/service/PublishArticleService.java
@@ -0,0 +1,10 @@
+package com.baeldung.service;
+
+import org.flowable.engine.delegate.DelegateExecution;
+import org.flowable.engine.delegate.JavaDelegate;
+
+public class PublishArticleService implements JavaDelegate {
+ public void execute(DelegateExecution execution) {
+ System.out.println("Publishing the approved article.");
+ }
+}
diff --git a/spring-boot-flowable/src/main/java/com/baeldung/service/SendMailService.java b/spring-boot-flowable/src/main/java/com/baeldung/service/SendMailService.java
new file mode 100644
index 0000000000..f80b16748f
--- /dev/null
+++ b/spring-boot-flowable/src/main/java/com/baeldung/service/SendMailService.java
@@ -0,0 +1,10 @@
+package com.baeldung.service;
+
+import org.flowable.engine.delegate.DelegateExecution;
+import org.flowable.engine.delegate.JavaDelegate;
+
+public class SendMailService implements JavaDelegate {
+ public void execute(DelegateExecution execution) {
+ System.out.println("Sending rejection mail to author.");
+ }
+}
diff --git a/spring-boot-flowable/src/main/resources/application.properties b/spring-boot-flowable/src/main/resources/application.properties
new file mode 100644
index 0000000000..c3afcaa0b5
--- /dev/null
+++ b/spring-boot-flowable/src/main/resources/application.properties
@@ -0,0 +1 @@
+management.endpoint.flowable.enabled=true
\ No newline at end of file
diff --git a/spring-boot-flowable/src/main/resources/processes/article-workflow.bpmn20.xml b/spring-boot-flowable/src/main/resources/processes/article-workflow.bpmn20.xml
new file mode 100644
index 0000000000..6bf210dcee
--- /dev/null
+++ b/spring-boot-flowable/src/main/resources/processes/article-workflow.bpmn20.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-boot-flowable/src/test/java/com/baeldung/processes/ArticleWorkflowUnitTest.java b/spring-boot-flowable/src/test/java/com/baeldung/processes/ArticleWorkflowUnitTest.java
new file mode 100644
index 0000000000..ef5453623a
--- /dev/null
+++ b/spring-boot-flowable/src/test/java/com/baeldung/processes/ArticleWorkflowUnitTest.java
@@ -0,0 +1,40 @@
+package com.baeldung.processes;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.TaskService;
+import org.flowable.engine.test.Deployment;
+import org.flowable.spring.impl.test.FlowableSpringExtension;
+import org.flowable.task.api.Task;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+@ExtendWith(FlowableSpringExtension.class)
+@ExtendWith(SpringExtension.class)
+public class ArticleWorkflowUnitTest {
+ @Autowired
+ private RuntimeService runtimeService;
+ @Autowired
+ private TaskService taskService;
+ @Test
+ @Deployment(resources = { "processes/article-workflow.bpmn20.xml" })
+ void articleApprovalTest() {
+ Map variables = new HashMap();
+ variables.put("author", "test@baeldung.com");
+ variables.put("url", "http://baeldung.com/dummy");
+ runtimeService.startProcessInstanceByKey("articleReview", variables);
+ Task task = taskService.createTaskQuery()
+ .singleResult();
+ assertEquals("Review the submitted tutorial", task.getName());
+ variables.put("approved", true);
+ taskService.complete(task.getId(), variables);
+ assertEquals(0, runtimeService.createProcessInstanceQuery()
+ .count());
+ }
+}
\ No newline at end of file
diff --git a/spring-boot-rest/README.md b/spring-boot-rest/README.md
index af372077f0..5b7bbdac60 100644
--- a/spring-boot-rest/README.md
+++ b/spring-boot-rest/README.md
@@ -1,13 +1,18 @@
Module for the articles that are part of the Spring REST E-book:
1. [Bootstrap a Web Application with Spring 5](https://www.baeldung.com/bootstraping-a-web-application-with-spring-and-java-based-configuration)
-2. [Error Handling for REST with Spring](http://www.baeldung.com/exception-handling-for-rest-with-spring)
-3. [REST Pagination in Spring](http://www.baeldung.com/rest-api-pagination-in-spring)
-4. [Build a REST API with Spring and Java Config](http://www.baeldung.com/building-a-restful-web-service-with-spring-and-java-based-configuration)
-5. [HATEOAS for a Spring REST Service](http://www.baeldung.com/rest-api-discoverability-with-spring)
-6. [REST API Discoverability and HATEOAS](http://www.baeldung.com/restful-web-service-discoverability)
-7. [Versioning a REST API](http://www.baeldung.com/rest-versioning)
-8. [Http Message Converters with the Spring Framework](http://www.baeldung.com/spring-httpmessageconverter-rest)
-9. [ETags for REST with Spring](http://www.baeldung.com/etags-for-rest-with-spring)
-10. [Testing REST with multiple MIME types](http://www.baeldung.com/testing-rest-api-with-multiple-media-types)
-11. [Testing Web APIs with Postman Collections](https://www.baeldung.com/postman-testing-collections)
+2. [Build a REST API with Spring and Java Config](http://www.baeldung.com/building-a-restful-web-service-with-spring-and-java-based-configuration)
+3. [Http Message Converters with the Spring Framework](http://www.baeldung.com/spring-httpmessageconverter-rest)
+4. [Spring’s RequestBody and ResponseBody Annotations](https://www.baeldung.com/spring-request-response-body)
+5. [Entity To DTO Conversion for a Spring REST API](https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application)
+6. [Error Handling for REST with Spring](http://www.baeldung.com/exception-handling-for-rest-with-spring)
+7. [REST API Discoverability and HATEOAS](http://www.baeldung.com/restful-web-service-discoverability)
+8.
+9. [REST Pagination in Spring](http://www.baeldung.com/rest-api-pagination-in-spring)
+10. [Test a REST API with Java](http://www.baeldung.com/integration-testing-a-rest-api)
+
+- [HATEOAS for a Spring REST Service](http://www.baeldung.com/rest-api-discoverability-with-spring)
+- [Versioning a REST API](http://www.baeldung.com/rest-versioning)
+- [ETags for REST with Spring](http://www.baeldung.com/etags-for-rest-with-spring)
+- [Testing REST with multiple MIME types](http://www.baeldung.com/testing-rest-api-with-multiple-media-types)
+- [Testing Web APIs with Postman Collections](https://www.baeldung.com/postman-testing-collections)
diff --git a/spring-boot-rest/pom.xml b/spring-boot-rest/pom.xml
index decaccd148..2bf7c0181f 100644
--- a/spring-boot-rest/pom.xml
+++ b/spring-boot-rest/pom.xml
@@ -63,6 +63,11 @@
htmlunit
test
+
+ org.modelmapper
+ modelmapper
+ ${modelmapper.version}
+
@@ -78,5 +83,6 @@
com.baeldung.SpringBootRestApplication
27.0.1-jre
1.4.11.1
+ 2.3.3
diff --git a/spring-boot-rest/src/main/java/com/baeldung/SpringBootRestApplication.java b/spring-boot-rest/src/main/java/com/baeldung/SpringBootRestApplication.java
index 62aae7619d..1c0d0d19e8 100644
--- a/spring-boot-rest/src/main/java/com/baeldung/SpringBootRestApplication.java
+++ b/spring-boot-rest/src/main/java/com/baeldung/SpringBootRestApplication.java
@@ -1,7 +1,9 @@
package com.baeldung;
+import org.modelmapper.ModelMapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class SpringBootRestApplication {
@@ -9,5 +11,10 @@ public class SpringBootRestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootRestApplication.class, args);
}
+
+ @Bean
+ public ModelMapper modelMapper() {
+ return new ModelMapper();
+ }
}
diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/controller/PostRestController.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/controller/PostRestController.java
similarity index 100%
rename from spring-boot/src/main/java/com/baeldung/modelmapper/controller/PostRestController.java
rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/controller/PostRestController.java
diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/dto/PostDto.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/dto/PostDto.java
similarity index 100%
rename from spring-boot/src/main/java/com/baeldung/modelmapper/dto/PostDto.java
rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/dto/PostDto.java
diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/dto/UserDto.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/dto/UserDto.java
similarity index 100%
rename from spring-boot/src/main/java/com/baeldung/modelmapper/dto/UserDto.java
rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/dto/UserDto.java
diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/model/Post.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/model/Post.java
similarity index 100%
rename from spring-boot/src/main/java/com/baeldung/modelmapper/model/Post.java
rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/model/Post.java
diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/model/Preference.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/model/Preference.java
similarity index 100%
rename from spring-boot/src/main/java/com/baeldung/modelmapper/model/Preference.java
rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/model/Preference.java
diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/model/User.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/model/User.java
similarity index 100%
rename from spring-boot/src/main/java/com/baeldung/modelmapper/model/User.java
rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/model/User.java
diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/repository/PostRepository.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/repository/PostRepository.java
similarity index 100%
rename from spring-boot/src/main/java/com/baeldung/modelmapper/repository/PostRepository.java
rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/repository/PostRepository.java
diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/service/IPostService.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/service/IPostService.java
similarity index 100%
rename from spring-boot/src/main/java/com/baeldung/modelmapper/service/IPostService.java
rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/service/IPostService.java
diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/service/IUserService.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/service/IUserService.java
similarity index 100%
rename from spring-boot/src/main/java/com/baeldung/modelmapper/service/IUserService.java
rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/service/IUserService.java
diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/service/PostService.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/service/PostService.java
similarity index 100%
rename from spring-boot/src/main/java/com/baeldung/modelmapper/service/PostService.java
rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/service/PostService.java
diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/service/UserService.java b/spring-boot-rest/src/main/java/com/baeldung/modelmapper/service/UserService.java
similarity index 100%
rename from spring-boot/src/main/java/com/baeldung/modelmapper/service/UserService.java
rename to spring-boot-rest/src/main/java/com/baeldung/modelmapper/service/UserService.java
diff --git a/spring-rest/src/main/java/com/baeldung/services/ExampleService.java b/spring-boot-rest/src/main/java/com/baeldung/services/ExampleService.java
similarity index 100%
rename from spring-rest/src/main/java/com/baeldung/services/ExampleService.java
rename to spring-boot-rest/src/main/java/com/baeldung/services/ExampleService.java
diff --git a/spring-boot-rest/src/main/java/com/baeldung/spring/PersistenceConfig.java b/spring-boot-rest/src/main/java/com/baeldung/spring/PersistenceConfig.java
index 5179c66978..2e967751ad 100644
--- a/spring-boot-rest/src/main/java/com/baeldung/spring/PersistenceConfig.java
+++ b/spring-boot-rest/src/main/java/com/baeldung/spring/PersistenceConfig.java
@@ -24,8 +24,8 @@ import com.google.common.base.Preconditions;
@Configuration
@EnableTransactionManagement
@PropertySource({ "classpath:persistence-${envTarget:h2}.properties" })
-@ComponentScan({ "com.baeldung.persistence" })
-@EnableJpaRepositories(basePackages = "com.baeldung.persistence.dao")
+@ComponentScan(basePackages = { "com.baeldung.persistence", "com.baeldung.modelmapper" })
+@EnableJpaRepositories(basePackages = {"com.baeldung.persistence.dao", "com.baeldung.modelmapper.repository"})
public class PersistenceConfig {
@Autowired
@@ -39,7 +39,7 @@ public class PersistenceConfig {
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
- em.setPackagesToScan(new String[] { "com.baeldung.persistence.model" });
+ em.setPackagesToScan(new String[] { "com.baeldung.persistence.model", "com.baeldung.modelmapper.model" });
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
// vendorAdapter.set
diff --git a/spring-boot-rest/src/main/java/com/baeldung/transfer/LoginForm.java b/spring-boot-rest/src/main/java/com/baeldung/transfer/LoginForm.java
new file mode 100644
index 0000000000..caafcdb500
--- /dev/null
+++ b/spring-boot-rest/src/main/java/com/baeldung/transfer/LoginForm.java
@@ -0,0 +1,31 @@
+package com.baeldung.transfer;
+
+public class LoginForm {
+ private String username;
+ private String password;
+
+ public LoginForm() {
+ }
+
+ public LoginForm(String username, String password) {
+ super();
+ this.username = username;
+ this.password = password;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+}
\ No newline at end of file
diff --git a/spring-rest/src/main/java/com/baeldung/transfer/ResponseTransfer.java b/spring-boot-rest/src/main/java/com/baeldung/transfer/ResponseTransfer.java
similarity index 100%
rename from spring-rest/src/main/java/com/baeldung/transfer/ResponseTransfer.java
rename to spring-boot-rest/src/main/java/com/baeldung/transfer/ResponseTransfer.java
diff --git a/spring-rest/src/main/java/com/baeldung/controllers/ExamplePostController.java b/spring-boot-rest/src/main/java/com/baeldung/web/controller/ExamplePostController.java
similarity index 97%
rename from spring-rest/src/main/java/com/baeldung/controllers/ExamplePostController.java
rename to spring-boot-rest/src/main/java/com/baeldung/web/controller/ExamplePostController.java
index 93f96756b4..1519d95d4d 100644
--- a/spring-rest/src/main/java/com/baeldung/controllers/ExamplePostController.java
+++ b/spring-boot-rest/src/main/java/com/baeldung/web/controller/ExamplePostController.java
@@ -1,4 +1,4 @@
-package com.baeldung.controllers;
+package com.baeldung.web.controller;
import com.baeldung.services.ExampleService;
import com.baeldung.transfer.ResponseTransfer;
diff --git a/spring-boot-rest/src/test/java/com/baeldung/SpringContextIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/SpringContextIntegrationTest.java
index 25fbc4cc02..3db1ecb462 100644
--- a/spring-boot-rest/src/test/java/com/baeldung/SpringContextIntegrationTest.java
+++ b/spring-boot-rest/src/test/java/com/baeldung/SpringContextIntegrationTest.java
@@ -6,7 +6,7 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
-@SpringBootTest
+@SpringBootTest(classes = {SpringBootRestApplication.class})
public class SpringContextIntegrationTest {
@Test
diff --git a/spring-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerRequestIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerRequestIntegrationTest.java
similarity index 92%
rename from spring-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerRequestIntegrationTest.java
rename to spring-boot-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerRequestIntegrationTest.java
index 94b8bf40e7..fc533072c8 100644
--- a/spring-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerRequestIntegrationTest.java
+++ b/spring-boot-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerRequestIntegrationTest.java
@@ -1,8 +1,10 @@
package com.baeldung.controllers;
-import com.baeldung.sampleapp.config.MainApplication;
-import com.baeldung.services.ExampleService;
-import com.baeldung.transfer.LoginForm;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -14,13 +16,13 @@ import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
-import static org.mockito.Mockito.when;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
-import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import com.baeldung.SpringBootRestApplication;
+import com.baeldung.services.ExampleService;
+import com.baeldung.transfer.LoginForm;
+import com.baeldung.web.controller.ExamplePostController;
@RunWith(SpringRunner.class)
-@SpringBootTest(classes = MainApplication.class)
+@SpringBootTest(classes = SpringBootRestApplication.class)
public class ExamplePostControllerRequestIntegrationTest {
MockMvc mockMvc;
diff --git a/spring-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerResponseIntegrationTest.java b/spring-boot-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerResponseIntegrationTest.java
similarity index 92%
rename from spring-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerResponseIntegrationTest.java
rename to spring-boot-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerResponseIntegrationTest.java
index 5743ad450b..cbe21b1d90 100644
--- a/spring-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerResponseIntegrationTest.java
+++ b/spring-boot-rest/src/test/java/com/baeldung/controllers/ExamplePostControllerResponseIntegrationTest.java
@@ -1,8 +1,11 @@
package com.baeldung.controllers;
-import com.baeldung.sampleapp.config.MainApplication;
-import com.baeldung.services.ExampleService;
-import com.baeldung.transfer.LoginForm;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -11,18 +14,16 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
-
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
-import static org.mockito.Mockito.when;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
-import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import com.baeldung.SpringBootRestApplication;
+import com.baeldung.services.ExampleService;
+import com.baeldung.transfer.LoginForm;
+import com.baeldung.web.controller.ExamplePostController;
@RunWith(SpringRunner.class)
-@SpringBootTest(classes = MainApplication.class)
+@SpringBootTest(classes = SpringBootRestApplication.class)
public class ExamplePostControllerResponseIntegrationTest {
MockMvc mockMvc;
diff --git a/spring-boot/src/test/java/com/baeldung/modelmapper/PostDtoUnitTest.java b/spring-boot-rest/src/test/java/com/baeldung/modelmapper/PostDtoUnitTest.java
similarity index 100%
rename from spring-boot/src/test/java/com/baeldung/modelmapper/PostDtoUnitTest.java
rename to spring-boot-rest/src/test/java/com/baeldung/modelmapper/PostDtoUnitTest.java
diff --git a/spring-boot-rest/src/test/java/com/baeldung/rest/GitHubUser.java b/spring-boot-rest/src/test/java/com/baeldung/rest/GitHubUser.java
new file mode 100644
index 0000000000..da5085ab12
--- /dev/null
+++ b/spring-boot-rest/src/test/java/com/baeldung/rest/GitHubUser.java
@@ -0,0 +1,21 @@
+package com.baeldung.rest;
+
+public class GitHubUser {
+
+ private String login;
+
+ public GitHubUser() {
+ super();
+ }
+
+ // API
+
+ public String getLogin() {
+ return login;
+ }
+
+ public void setLogin(final String login) {
+ this.login = login;
+ }
+
+}
diff --git a/testing-modules/rest-testing/src/test/java/org/baeldung/rest/GithubBasicLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/rest/GithubBasicLiveTest.java
similarity index 98%
rename from testing-modules/rest-testing/src/test/java/org/baeldung/rest/GithubBasicLiveTest.java
rename to spring-boot-rest/src/test/java/com/baeldung/rest/GithubBasicLiveTest.java
index acac82c8f4..3082b34421 100644
--- a/testing-modules/rest-testing/src/test/java/org/baeldung/rest/GithubBasicLiveTest.java
+++ b/spring-boot-rest/src/test/java/com/baeldung/rest/GithubBasicLiveTest.java
@@ -1,4 +1,4 @@
-package org.baeldung.rest;
+package com.baeldung.rest;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import static org.hamcrest.Matchers.equalTo;
diff --git a/spring-boot-rest/src/test/java/com/baeldung/rest/RetrieveUtil.java b/spring-boot-rest/src/test/java/com/baeldung/rest/RetrieveUtil.java
new file mode 100644
index 0000000000..0ec36bc3ae
--- /dev/null
+++ b/spring-boot-rest/src/test/java/com/baeldung/rest/RetrieveUtil.java
@@ -0,0 +1,21 @@
+package com.baeldung.rest;
+
+import java.io.IOException;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.util.EntityUtils;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class RetrieveUtil {
+
+ // API
+
+ public static T retrieveResourceFromResponse(final HttpResponse response, final Class clazz) throws IOException {
+ final String jsonFromResponse = EntityUtils.toString(response.getEntity());
+ final ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ return mapper.readValue(jsonFromResponse, clazz);
+ }
+
+}
diff --git a/spring-boot/README.MD b/spring-boot/README.MD
index 7d270c9c25..c0392d38de 100644
--- a/spring-boot/README.MD
+++ b/spring-boot/README.MD
@@ -6,12 +6,12 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [A Guide to Spring in Eclipse STS](http://www.baeldung.com/eclipse-sts-spring)
- [The @ServletComponentScan Annotation in Spring Boot](http://www.baeldung.com/spring-servletcomponentscan)
- [Intro to Building an Application with Spring Boot](http://www.baeldung.com/intro-to-spring-boot)
-- [How to Register a Servlet in a Java Web Application](http://www.baeldung.com/register-servlet)
+- [How to Register a Servlet in Java](http://www.baeldung.com/register-servlet)
- [Guide to Spring WebUtils and ServletRequestUtils](http://www.baeldung.com/spring-webutils-servletrequestutils)
- [Using Custom Banners in Spring Boot](http://www.baeldung.com/spring-boot-custom-banners)
- [Guide to Internationalization in Spring Boot](http://www.baeldung.com/spring-boot-internationalization)
- [Create a Custom FailureAnalyzer with Spring Boot](http://www.baeldung.com/spring-boot-failure-analyzer)
-- [Dynamic DTO Validation Config Retrieved from DB](http://www.baeldung.com/spring-dynamic-dto-validation)
+- [Dynamic DTO Validation Config Retrieved from the Database](http://www.baeldung.com/spring-dynamic-dto-validation)
- [Custom Information in Spring Boot Info Endpoint](http://www.baeldung.com/spring-boot-info-actuator-custom)
- [Using @JsonComponent in Spring Boot](http://www.baeldung.com/spring-boot-jsoncomponent)
- [Testing in Spring Boot](http://www.baeldung.com/spring-boot-testing)
@@ -21,7 +21,7 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Getting Started with GraphQL and Spring Boot](http://www.baeldung.com/spring-graphql)
- [Guide to Spring Type Conversions](http://www.baeldung.com/spring-type-conversions)
- [An Introduction to Kong](http://www.baeldung.com/kong)
-- [Spring Boot Customize Whitelabel Error Page](http://www.baeldung.com/spring-boot-custom-error-page)
+- [Spring Boot: Customize Whitelabel Error Page](http://www.baeldung.com/spring-boot-custom-error-page)
- [Spring Boot: Configuring a Main Class](http://www.baeldung.com/spring-boot-main-class)
- [A Quick Intro to the SpringBootServletInitializer](http://www.baeldung.com/spring-boot-servlet-initializer)
- [How to Define a Spring Boot Filter?](http://www.baeldung.com/spring-boot-add-filter)
@@ -35,5 +35,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Display Auto-Configuration Report in Spring Boot](https://www.baeldung.com/spring-boot-auto-configuration-report)
- [Injecting Git Information Into Spring](https://www.baeldung.com/spring-git-information)
- [Validation in Spring Boot](https://www.baeldung.com/spring-boot-bean-validation)
-- [Entity To DTO Conversion for a Spring REST API](https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application)
- [Guide to Creating and Running a Jar File in Java](https://www.baeldung.com/java-create-jar)
diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml
index ed2d8259df..401e0289e8 100644
--- a/spring-boot/pom.xml
+++ b/spring-boot/pom.xml
@@ -153,12 +153,6 @@
javax.validation
validation-api
-
-
- org.modelmapper
- modelmapper
- ${modelmapper.version}
-
@@ -256,7 +250,6 @@
5.2.4
18.0
2.2.4
- 2.3.2
diff --git a/spring-boot/src/main/java/com/baeldung/modelmapper/PostApplication.java b/spring-boot/src/main/java/com/baeldung/modelmapper/PostApplication.java
deleted file mode 100644
index 7684c43648..0000000000
--- a/spring-boot/src/main/java/com/baeldung/modelmapper/PostApplication.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.baeldung.modelmapper;
-
-import org.modelmapper.ModelMapper;
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.context.annotation.Bean;
-
-@SpringBootApplication
-public class PostApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(PostApplication.class, args);
- }
-
- @Bean
- public ModelMapper modelMapper() {
- return new ModelMapper();
- }
-
-}
diff --git a/spring-cloud/spring-cloud-config/client/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-config/client/src/test/java/com/baeldung/spring/cloud/config/client/SpringContextLiveTest.java
similarity index 69%
rename from spring-cloud/spring-cloud-config/client/src/test/java/org/baeldung/SpringContextIntegrationTest.java
rename to spring-cloud/spring-cloud-config/client/src/test/java/com/baeldung/spring/cloud/config/client/SpringContextLiveTest.java
index d727772cf9..3fb43b169d 100644
--- a/spring-cloud/spring-cloud-config/client/src/test/java/org/baeldung/SpringContextIntegrationTest.java
+++ b/spring-cloud/spring-cloud-config/client/src/test/java/com/baeldung/spring/cloud/config/client/SpringContextLiveTest.java
@@ -1,4 +1,4 @@
-package org.baeldung;
+package com.baeldung.spring.cloud.config.client;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -6,12 +6,15 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
-import com.baeldung.spring.cloud.config.client.ConfigClient;
-
+/**
+ *
+ * The app needs the server running on port 8888. Can be started with docker
+ *
+ */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = ConfigClient.class)
@WebAppConfiguration
-public class SpringContextIntegrationTest {
+public class SpringContextLiveTest {
@Test
public void contextLoads() {
}
diff --git a/spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/SpringContextLiveTest.java b/spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/SpringContextIntegrationTest.java
similarity index 79%
rename from spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/SpringContextLiveTest.java
rename to spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/SpringContextIntegrationTest.java
index 793b4abb6c..b2c6ef85ea 100644
--- a/spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/SpringContextLiveTest.java
+++ b/spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/SpringContextIntegrationTest.java
@@ -6,16 +6,10 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
-
-/**
- *
- * The context will load successfully with some properties provided by docker
- *
- */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = ConfigServer.class)
@WebAppConfiguration
-public class SpringContextLiveTest {
+public class SpringContextIntegrationTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
diff --git a/spring-cloud/spring-cloud-config/server/src/test/resources/application.properties b/spring-cloud/spring-cloud-config/server/src/test/resources/application.properties
new file mode 100644
index 0000000000..67cc81ff67
--- /dev/null
+++ b/spring-cloud/spring-cloud-config/server/src/test/resources/application.properties
@@ -0,0 +1,2 @@
+### This should be provided by the docker config
+spring.cloud.config.server.git.uri=classpath:.
diff --git a/spring-cloud/spring-cloud-connectors-heroku/src/main/resources/application.properties b/spring-cloud/spring-cloud-connectors-heroku/src/main/resources/application.properties
index d2f1c89dc5..571f325824 100644
--- a/spring-cloud/spring-cloud-connectors-heroku/src/main/resources/application.properties
+++ b/spring-cloud/spring-cloud-connectors-heroku/src/main/resources/application.properties
@@ -4,5 +4,6 @@ spring.datasource.maxIdle=5
spring.datasource.minIdle=2
spring.datasource.initialSize=5
spring.datasource.removeAbandoned=true
+spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-connectors-heroku/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-connectors-heroku/src/test/java/com/baeldung/spring/cloud/connectors/heroku/SpringContextIntegrationTest.java
similarity index 90%
rename from spring-cloud/spring-cloud-connectors-heroku/src/test/java/org/baeldung/SpringContextIntegrationTest.java
rename to spring-cloud/spring-cloud-connectors-heroku/src/test/java/com/baeldung/spring/cloud/connectors/heroku/SpringContextIntegrationTest.java
index a705f18bc6..dca4c25c71 100644
--- a/spring-cloud/spring-cloud-connectors-heroku/src/test/java/org/baeldung/SpringContextIntegrationTest.java
+++ b/spring-cloud/spring-cloud-connectors-heroku/src/test/java/com/baeldung/spring/cloud/connectors/heroku/SpringContextIntegrationTest.java
@@ -1,4 +1,4 @@
-package org.baeldung;
+package com.baeldung.spring.cloud.connectors.heroku;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/spring-cloud/spring-cloud-connectors-heroku/src/test/resources/application.properties b/spring-cloud/spring-cloud-connectors-heroku/src/test/resources/application.properties
new file mode 100644
index 0000000000..7b139ae07d
--- /dev/null
+++ b/spring-cloud/spring-cloud-connectors-heroku/src/test/resources/application.properties
@@ -0,0 +1,2 @@
+spring.jpa.hibernate.ddl-auto=create
+spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-consul/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-consul/src/test/java/com/baeldung/spring/cloud/consul/SpringContextLiveTest.java
similarity index 74%
rename from spring-cloud/spring-cloud-consul/src/test/java/org/baeldung/SpringContextIntegrationTest.java
rename to spring-cloud/spring-cloud-consul/src/test/java/com/baeldung/spring/cloud/consul/SpringContextLiveTest.java
index 6290ccc03e..7c87add43e 100644
--- a/spring-cloud/spring-cloud-consul/src/test/java/org/baeldung/SpringContextIntegrationTest.java
+++ b/spring-cloud/spring-cloud-consul/src/test/java/com/baeldung/spring/cloud/consul/SpringContextLiveTest.java
@@ -1,4 +1,4 @@
-package org.baeldung;
+package com.baeldung.spring.cloud.consul;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -9,10 +9,18 @@ import com.baeldung.spring.cloud.consul.discovery.DiscoveryClientApplication;
import com.baeldung.spring.cloud.consul.health.ServiceDiscoveryApplication;
import com.baeldung.spring.cloud.consul.properties.DistributedPropertiesApplication;
+
+/**
+ *
+ * This Live test requires:
+ * * a Consul instance running on port 8500
+ * * Consul configured with particular properties (e.g. 'my.prop')
+ *
+ */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = { DiscoveryClientApplication.class, ServiceDiscoveryApplication.class,
DistributedPropertiesApplication.class })
-public class SpringContextIntegrationTest {
+public class SpringContextLiveTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
diff --git a/spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextLiveTest.java
similarity index 66%
rename from spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java
rename to spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextLiveTest.java
index 24e758ff82..eb56c16c6a 100644
--- a/spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java
+++ b/spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextLiveTest.java
@@ -5,9 +5,15 @@ import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
+/**
+ *
+ * This Live Test requires:
+ * * A Redis instance running in port 6379 (e.g. using `docker run --name some-redis -p 6379:6379 -d redis`)
+ *
+ */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = BooksApiApplication.class)
-public class SpringContextIntegrationTest {
+public class SpringContextLiveTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
diff --git a/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextLiveTest.java
similarity index 67%
rename from spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextIntegrationTest.java
rename to spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextLiveTest.java
index e22359a016..01266a3bda 100644
--- a/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextIntegrationTest.java
+++ b/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextLiveTest.java
@@ -5,9 +5,15 @@ import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
+/**
+ *
+ * This Live Test requires:
+ * * A Redis instance running in port 6379 (e.g. using `docker run --name some-redis -p 6379:6379 -d redis`)
+ *
+ */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringCloudRestServerApplication.class)
-public class SpringContextIntegrationTest {
+public class SpringContextLiveTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
diff --git a/spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextLiveTest.java b/spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextLiveTest.java
new file mode 100644
index 0000000000..070abd246f
--- /dev/null
+++ b/spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextLiveTest.java
@@ -0,0 +1,21 @@
+package org.baeldung;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ *
+ * This Live Test requires:
+ * * A Redis instance running in port 6379 (e.g. using `docker run --name some-redis -p 6379:6379 -d redis`)
+ *
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = BookReviewsApiApplication.class)
+public class SpringContextLiveTest {
+
+ @Test
+ public void whenSpringContextIsBootstrapped_thenNoExceptions() {
+ }
+}
diff --git a/spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/com/baeldung/twitterhdfs/aggregate/SpringContextIntegrationTest.java
similarity index 79%
rename from spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java
rename to spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/com/baeldung/twitterhdfs/aggregate/SpringContextIntegrationTest.java
index 07d7db0505..b5cef1b5ed 100644
--- a/spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java
+++ b/spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/com/baeldung/twitterhdfs/aggregate/SpringContextIntegrationTest.java
@@ -1,4 +1,4 @@
-package org.baeldung;
+package com.baeldung.twitterhdfs.aggregate;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -6,7 +6,7 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
-@SpringBootTest(classes = BookReviewsApiApplication.class)
+@SpringBootTest(classes = AggregateApp.class)
public class SpringContextIntegrationTest {
@Test
diff --git a/spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/org/baeldung/SpringContextIntegrationTest.java
deleted file mode 100644
index 3d370e7b48..0000000000
--- a/spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/org/baeldung/SpringContextIntegrationTest.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.baeldung;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-
-import com.baeldung.twitterhdfs.aggregate.AggregateApp;
-import com.baeldung.twitterhdfs.processor.ProcessorApp;
-import com.baeldung.twitterhdfs.sink.SinkApp;
-import com.baeldung.twitterhdfs.source.SourceApp;
-
-@RunWith(SpringRunner.class)
-@SpringBootTest(classes = {AggregateApp.class, ProcessorApp.class, SinkApp.class, SourceApp.class})
-public class SpringContextIntegrationTest {
-
- @Test
- public void whenSpringContextIsBootstrapped_thenNoExceptions() {
- }
-}
diff --git a/spring-cloud/spring-cloud-zookeeper/README.md b/spring-cloud/spring-cloud-zookeeper/README.md
index a639833452..a49a448833 100644
--- a/spring-cloud/spring-cloud-zookeeper/README.md
+++ b/spring-cloud/spring-cloud-zookeeper/README.md
@@ -1,2 +1,2 @@
### Relevant Articles:
-- [An Introduction to Spring Cloud Zookeeper](http://www.baeldung.com/spring-cloud-zookeeper)
+- [An Intro to Spring Cloud Zookeeper](http://www.baeldung.com/spring-cloud-zookeeper)
diff --git a/spring-data-rest/pom.xml b/spring-data-rest/pom.xml
index e563a6a3b5..525c88c9d8 100644
--- a/spring-data-rest/pom.xml
+++ b/spring-data-rest/pom.xml
@@ -1,9 +1,8 @@
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
spring-data-rest
-
1.0
spring-data-rest
jar
@@ -21,6 +20,10 @@
org.springframework.boot
spring-boot-starter
+
+ org.springframework.boot
+ spring-boot-starter-web
+
org.springframework.boot
spring-boot-starter-data-rest
@@ -30,12 +33,21 @@
spring-boot-starter-data-jpa
- com.h2database
- h2
+ org.springframework.boot
+ spring-boot-autoconfigure
org.springframework.boot
- spring-boot-autoconfigure
+ spring-boot-starter-test
+ test
+
+
+ com.querydsl
+ querydsl-apt
+
+
+ com.querydsl
+ querydsl-jpa
org.xerial
@@ -45,9 +57,33 @@
${project.artifactId}
+
+
+ com.mysema.maven
+ maven-apt-plugin
+ 1.0
+
+
+ generate-sources
+
+ process
+
+
+ target/generated-sources
+ com.querydsl.apt.jpa.JPAAnnotationProcessor
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ UTF-8
com.baeldung.SpringDataRestApplication
diff --git a/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/Application.java b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/Application.java
new file mode 100644
index 0000000000..fe2f996d37
--- /dev/null
+++ b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/Application.java
@@ -0,0 +1,28 @@
+package com.baeldung.springdatawebsupport.application;
+
+import com.baeldung.springdatawebsupport.application.entities.User;
+import com.baeldung.springdatawebsupport.application.repositories.UserRepository;
+import java.util.stream.Stream;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+ @Bean
+ CommandLineRunner initialize(UserRepository userRepository) {
+ return args -> {
+ Stream.of("John", "Robert", "Nataly", "Helen", "Mary").forEach(name -> {
+ User user = new User(name);
+ userRepository.save(user);
+ });
+ userRepository.findAll().forEach(System.out::println);
+ };
+ }
+}
diff --git a/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/controllers/UserController.java b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/controllers/UserController.java
new file mode 100644
index 0000000000..8258c3b7aa
--- /dev/null
+++ b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/controllers/UserController.java
@@ -0,0 +1,47 @@
+package com.baeldung.springdatawebsupport.application.controllers;
+
+import com.baeldung.springdatawebsupport.application.entities.User;
+import com.baeldung.springdatawebsupport.application.repositories.UserRepository;
+import com.querydsl.core.types.Predicate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.querydsl.binding.QuerydslPredicate;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class UserController {
+
+ private final UserRepository userRepository;
+
+ @Autowired
+ public UserController(UserRepository userRepository) {
+ this.userRepository = userRepository;
+ }
+
+ @GetMapping("/users/{id}")
+ public User findUserById(@PathVariable("id") User user) {
+ return user;
+ }
+
+ @GetMapping("/users")
+ public Page findAllUsers(Pageable pageable) {
+ return userRepository.findAll(pageable);
+ }
+
+ @GetMapping("/sortedusers")
+ public Page findAllUsersSortedByName() {
+ Pageable pageable = PageRequest.of(0, 5, Sort.by("name"));
+ return userRepository.findAll(pageable);
+ }
+
+ @GetMapping("/filteredusers")
+ public Iterable getUsersByQuerydslPredicate(@QuerydslPredicate(root = User.class) Predicate predicate) {
+ return userRepository.findAll(predicate);
+ }
+}
diff --git a/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/entities/User.java b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/entities/User.java
new file mode 100644
index 0000000000..e9aaeb119a
--- /dev/null
+++ b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/entities/User.java
@@ -0,0 +1,38 @@
+package com.baeldung.springdatawebsupport.application.entities;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "users")
+public class User {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private long id;
+ private final String name;
+
+ public User() {
+ this.name = "";
+ }
+
+ public User(String name) {
+ this.name = name;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return "User{" + "id=" + id + ", name=" + name + '}';
+ }
+}
diff --git a/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/repositories/UserRepository.java b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/repositories/UserRepository.java
new file mode 100644
index 0000000000..41d7ed9d98
--- /dev/null
+++ b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/repositories/UserRepository.java
@@ -0,0 +1,14 @@
+package com.baeldung.springdatawebsupport.application.repositories;
+
+import com.baeldung.springdatawebsupport.application.entities.User;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.querydsl.QuerydslPredicateExecutor;
+import org.springframework.data.repository.PagingAndSortingRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface UserRepository extends PagingAndSortingRepository,
+ QuerydslPredicateExecutor {
+
+}
diff --git a/spring-data-rest/src/test/java/com/baeldung/springdatawebsupport/application/test/UserControllerIntegrationTest.java b/spring-data-rest/src/test/java/com/baeldung/springdatawebsupport/application/test/UserControllerIntegrationTest.java
new file mode 100644
index 0000000000..db522b1413
--- /dev/null
+++ b/spring-data-rest/src/test/java/com/baeldung/springdatawebsupport/application/test/UserControllerIntegrationTest.java
@@ -0,0 +1,74 @@
+package com.baeldung.springdatawebsupport.application.test;
+
+import com.baeldung.springdatawebsupport.application.controllers.UserController;
+import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@AutoConfigureMockMvc
+public class UserControllerIntegrationTest {
+
+ @Autowired
+ private UserController userController;
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Test
+ public void whenUserControllerInjected_thenNotNull() throws Exception {
+ assertThat(userController).isNotNull();
+ }
+
+ @Test
+ public void whenGetRequestToUsersEndPointWithIdPathVariable_thenCorrectResponse() throws Exception {
+ mockMvc.perform(MockMvcRequestBuilders.get("/users/{id}", "1")
+ .contentType(MediaType.APPLICATION_JSON_UTF8))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$.id").value("1"));
+ }
+
+ @Test
+ public void whenGetRequestToUsersEndPoint_thenCorrectResponse() throws Exception {
+ mockMvc.perform(MockMvcRequestBuilders.get("/users")
+ .contentType(MediaType.APPLICATION_JSON_UTF8))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$['pageable']['paged']").value("true"));
+
+ }
+
+ @Test
+ public void whenGetRequestToUserEndPointWithNameRequestParameter_thenCorrectResponse() throws Exception {
+ mockMvc.perform(MockMvcRequestBuilders.get("/user")
+ .param("name", "John")
+ .contentType(MediaType.APPLICATION_JSON_UTF8))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$['content'][0].['name']").value("John"));
+ }
+
+ @Test
+ public void whenGetRequestToSorteredUsersEndPoint_thenCorrectResponse() throws Exception {
+ mockMvc.perform(MockMvcRequestBuilders.get("/sortedusers")
+ .contentType(MediaType.APPLICATION_JSON_UTF8))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$['sort']['sorted']").value("true"));
+ }
+
+ @Test
+ public void whenGetRequestToFilteredUsersEndPoint_thenCorrectResponse() throws Exception {
+ mockMvc.perform(MockMvcRequestBuilders.get("/filteredusers")
+ .param("name", "John")
+ .contentType(MediaType.APPLICATION_JSON_UTF8))
+ .andExpect(MockMvcResultMatchers.status().isOk())
+ .andExpect(MockMvcResultMatchers.jsonPath("$[0].name").value("John"));
+ }
+}
diff --git a/spring-mvc-java/README.md b/spring-mvc-java/README.md
index 497b0f4c1f..3deeb21afc 100644
--- a/spring-mvc-java/README.md
+++ b/spring-mvc-java/README.md
@@ -19,7 +19,7 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Introduction to HtmlUnit](http://www.baeldung.com/htmlunit)
- [Spring @RequestMapping New Shortcut Annotations](http://www.baeldung.com/spring-new-requestmapping-shortcuts)
- [Guide to Spring Handler Mappings](http://www.baeldung.com/spring-handler-mappings)
-- [Uploading and Displaying Excel Files with Spring MVC](http://www.baeldung.com/spring-mvc-excel-files)
+- [Upload and Display Excel Files with Spring MVC](http://www.baeldung.com/spring-mvc-excel-files)
- [Spring MVC Custom Validation](http://www.baeldung.com/spring-mvc-custom-validator)
- [web.xml vs Initializer with Spring](http://www.baeldung.com/spring-xml-vs-java-config)
- [The HttpMediaTypeNotAcceptableException in Spring MVC](http://www.baeldung.com/spring-httpmediatypenotacceptable)
@@ -31,3 +31,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Using Spring @ResponseStatus to Set HTTP Status Code](http://www.baeldung.com/spring-response-status)
- [Spring MVC Tutorial](https://www.baeldung.com/spring-mvc-tutorial)
- [Working with Date Parameters in Spring](https://www.baeldung.com/spring-date-parameters)
+- [A Java Web Application Without a web.xml](https://www.baeldung.com/java-web-app-without-web-xml)
diff --git a/spring-mvc-xml/README.md b/spring-mvc-xml/README.md
index dbc6125424..216517f52d 100644
--- a/spring-mvc-xml/README.md
+++ b/spring-mvc-xml/README.md
@@ -14,3 +14,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Guide to JavaServer Pages (JSP)](http://www.baeldung.com/jsp)
- [Exploring SpringMVC’s Form Tag Library](http://www.baeldung.com/spring-mvc-form-tags)
- [web.xml vs Initializer with Spring](http://www.baeldung.com/spring-xml-vs-java-config)
+- [A Java Web Application Without a web.xml](https://www.baeldung.com/java-web-app-without-web-xml)
diff --git a/spring-rest-shell/README.md b/spring-rest-shell/README.md
index 901d9a51ee..b250f06a4b 100644
--- a/spring-rest-shell/README.md
+++ b/spring-rest-shell/README.md
@@ -2,4 +2,4 @@
### Relevant Articles
-- [Spring REST Shell](http://www.baeldung.com/spring-rest-shell)
\ No newline at end of file
+- [Introduction to Spring REST Shell](http://www.baeldung.com/spring-rest-shell)
diff --git a/spring-rest/README.md b/spring-rest/README.md
index 9a2c1fd96c..6d3aac3eb8 100644
--- a/spring-rest/README.md
+++ b/spring-rest/README.md
@@ -20,5 +20,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Using the Spring RestTemplate Interceptor](http://www.baeldung.com/spring-rest-template-interceptor)
- [Get and Post Lists of Objects with RestTemplate](http://www.baeldung.com/spring-rest-template-list)
- [How to Set a Header on a Response with Spring 5](http://www.baeldung.com/spring-response-header)
-- [Spring’s RequestBody and ResponseBody Annotations](https://www.baeldung.com/spring-request-response-body)
- [Uploading MultipartFile with Spring RestTemplate](http://www.baeldung.com/spring-rest-template-multipart-upload)
diff --git a/spring-security-mvc-ldap/README.md b/spring-security-mvc-ldap/README.md
index ac080c138d..6f03143183 100644
--- a/spring-security-mvc-ldap/README.md
+++ b/spring-security-mvc-ldap/README.md
@@ -5,7 +5,7 @@
The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
### Relevant Article:
-- [Spring Security - security none, filters none, access permitAll](http://www.baeldung.com/security-none-filters-none-access-permitAll)
+- [Spring Security – security none, filters none, access permitAll](http://www.baeldung.com/security-none-filters-none-access-permitAll)
- [Intro to Spring Security LDAP](http://www.baeldung.com/spring-security-ldap)
### Notes
diff --git a/spring-security-mvc-login/README.md b/spring-security-mvc-login/README.md
index c19cbc87a5..983d949cb8 100644
--- a/spring-security-mvc-login/README.md
+++ b/spring-security-mvc-login/README.md
@@ -10,7 +10,7 @@ The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
- [Spring Security Logout](http://www.baeldung.com/spring-security-logout)
- [Spring Security Expressions – hasRole Example](http://www.baeldung.com/spring-security-expressions-basic)
- [Spring HTTP/HTTPS Channel Security](http://www.baeldung.com/spring-channel-security-https)
-- [Spring Security - Customize the 403 Forbidden/Access Denied Page](http://www.baeldung.com/spring-security-custom-access-denied-page)
+- [Spring Security – Customize the 403 Forbidden/Access Denied Page](http://www.baeldung.com/spring-security-custom-access-denied-page)
- [Spring Security – Redirect to the Previous URL After Login](http://www.baeldung.com/spring-security-redirect-login)
- [Spring Security Custom AuthenticationFailureHandler](http://www.baeldung.com/spring-security-custom-authentication-failure-handler)
diff --git a/spring-security-mvc-persisted-remember-me/README.md b/spring-security-mvc-persisted-remember-me/README.md
index e505537be1..db2ae890f9 100644
--- a/spring-security-mvc-persisted-remember-me/README.md
+++ b/spring-security-mvc-persisted-remember-me/README.md
@@ -6,7 +6,7 @@
The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
### Relevant Articles:
-- [Spring Security Persisted Remember Me](http://www.baeldung.com/spring-security-persistent-remember-me)
+- [Spring Security – Persistent Remember Me](http://www.baeldung.com/spring-security-persistent-remember-me)
### Build the Project
```
diff --git a/spring-security-sso/README.md b/spring-security-sso/README.md
index 11b5f011d5..d0c1b2f7cf 100644
--- a/spring-security-sso/README.md
+++ b/spring-security-sso/README.md
@@ -1,2 +1,2 @@
### Relevant Articles:
-- [Simple Single Sign On with Spring Security OAuth2](http://www.baeldung.com/sso-spring-security-oauth2)
+- [Simple Single Sign-On with Spring Security OAuth2](http://www.baeldung.com/sso-spring-security-oauth2)
diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/KerberosClientApp.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/KerberosClientApp.java
index a353961854..9fb86e7658 100644
--- a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/KerberosClientApp.java
+++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/KerberosClientApp.java
@@ -12,6 +12,8 @@ class KerberosClientApp {
System.setProperty("java.security.krb5.conf",
Paths.get(".\\krb-test-workdir\\krb5.conf").normalize().toAbsolutePath().toString());
System.setProperty("sun.security.krb5.debug", "true");
+ // disable usage of local kerberos ticket cache
+ System.setProperty("http.use.global.creds", "false");
}
public static void main(String[] args) {
diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleService.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleClient.java
similarity index 87%
rename from spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleService.java
rename to spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleClient.java
index 4145cf0c1a..745193e3b0 100644
--- a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleService.java
+++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleClient.java
@@ -5,14 +5,14 @@ import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
-class SampleService {
+class SampleClient {
@Value("${app.access-url}")
private String endpoint;
private RestTemplate restTemplate;
- public SampleService(RestTemplate restTemplate) {
+ public SampleClient(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
diff --git a/spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleServiceManualTest.java b/spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleClientManualTest.java
similarity index 59%
rename from spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleServiceManualTest.java
rename to spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleClientManualTest.java
index d0d9f0ae4b..fdb1b12531 100644
--- a/spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleServiceManualTest.java
+++ b/spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleClientManualTest.java
@@ -1,6 +1,5 @@
package kerberos.client;
-import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@@ -10,7 +9,6 @@ import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import static org.junit.Assert.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
@@ -23,21 +21,19 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-@FixMethodOrder
-public class SampleServiceManualTest {
+public class SampleClientManualTest {
@Autowired
- private SampleService sampleService;
+ private SampleClient sampleClient;
@Test
- public void a_givenKerberizedRestTemplate_whenServiceCall_thenSuccess() {
- assertNotNull(sampleService);
- assertEquals("data from kerberized server", sampleService.getData());
+ public void givenKerberizedRestTemplate_whenServiceCall_thenSuccess() {
+ assertEquals("data from kerberized server", sampleClient.getData());
}
@Test
- public void b_givenRestTemplate_whenServiceCall_thenFail() {
- sampleService.setRestTemplate(new RestTemplate());
- assertThrows(RestClientException.class, sampleService::getData);
+ public void givenRestTemplate_whenServiceCall_thenFail() {
+ sampleClient.setRestTemplate(new RestTemplate());
+ assertThrows(RestClientException.class, sampleClient::getData);
}
}
\ No newline at end of file
diff --git a/spring-thymeleaf/README.md b/spring-thymeleaf/README.md
index f9e7dd90a7..b6824003db 100644
--- a/spring-thymeleaf/README.md
+++ b/spring-thymeleaf/README.md
@@ -8,7 +8,7 @@
- [Thymeleaf: Custom Layout Dialect](http://www.baeldung.com/thymeleaf-spring-layouts)
- [Spring and Thymeleaf 3: Expressions](http://www.baeldung.com/spring-thymeleaf-3-expressions)
- [Spring MVC + Thymeleaf 3.0: New Features](http://www.baeldung.com/spring-thymeleaf-3)
-- [How to Work with Dates in Thymeleaef](http://www.baeldung.com/dates-in-thymeleaf)
+- [How to Work with Dates in Thymeleaf](http://www.baeldung.com/dates-in-thymeleaf)
- [How to Create an Executable JAR with Maven](http://www.baeldung.com/executable-jar-with-maven)
- [Working with Boolean in Thymeleaf](http://www.baeldung.com/thymeleaf-boolean)
- [Working with Fragments in Thymeleaf](http://www.baeldung.com/spring-thymeleaf-fragments)
diff --git a/tensorflow-java/README.md b/tensorflow-java/README.md
index aa9e9e56b9..f826375ac1 100644
--- a/tensorflow-java/README.md
+++ b/tensorflow-java/README.md
@@ -1,3 +1,3 @@
## Relevant articles:
-- [TensorFlow for Java](https://www.baeldung.com/tensorflow-java)
+- [Introduction to Tensorflow for Java](https://www.baeldung.com/tensorflow-java)
diff --git a/testing-modules/groovy-spock/pom.xml b/testing-modules/groovy-spock/pom.xml
index d6097af208..35d8f5034f 100644
--- a/testing-modules/groovy-spock/pom.xml
+++ b/testing-modules/groovy-spock/pom.xml
@@ -48,7 +48,7 @@
- 1.3-RC1-groovy-2.4
+ 1.3-groovy-2.4
2.4.7
1.5
diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreIfTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreIfTest.groovy
index 91da2ff1ec..9010481220 100644
--- a/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreIfTest.groovy
+++ b/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreIfTest.groovy
@@ -7,6 +7,16 @@ import spock.lang.Specification
class IgnoreIfTest extends Specification {
@IgnoreIf({System.getProperty("os.name").contains("windows")})
- def "I won't run on windows"() { }
+ def "I won't run on windows"() {
+ expect:
+ true
+ }
+
+ @IgnoreIf({ os.isWindows() })
+ def "I'm using Spock helper classes to run only on windows"() {
+ expect:
+ true
+ }
+
}
diff --git a/testing-modules/groovy-spock/src/test/resources/SpockConfig.groovy b/testing-modules/groovy-spock/src/test/resources/SpockConfig.groovy
index ed94e61cbf..4b017aeefc 100644
--- a/testing-modules/groovy-spock/src/test/resources/SpockConfig.groovy
+++ b/testing-modules/groovy-spock/src/test/resources/SpockConfig.groovy
@@ -2,7 +2,10 @@ import extensions.TimeoutTest
import spock.lang.Issue
runner {
- filterStackTrace true
+
+ if (System.getenv("FILTER_STACKTRACE") == null) {
+ filterStackTrace false
+ }
report {
issueNamePrefix 'Bug '
diff --git a/testing-modules/junit-5/README.md b/testing-modules/junit-5/README.md
index d686396a1d..aafdd75e81 100644
--- a/testing-modules/junit-5/README.md
+++ b/testing-modules/junit-5/README.md
@@ -6,7 +6,7 @@
- [A Guide to JUnit 5 Extensions](http://www.baeldung.com/junit-5-extensions)
- [Inject Parameters into JUnit Jupiter Unit Tests](http://www.baeldung.com/junit-5-parameters)
- [Mockito and JUnit 5 – Using ExtendWith](http://www.baeldung.com/mockito-junit-5-extension)
-- [JUnit 5 – @RunWith](http://www.baeldung.com/junit-5-runwith)
+- [JUnit 5 @RunWith](http://www.baeldung.com/junit-5-runwith)
- [JUnit 5 @Test Annotation](http://www.baeldung.com/junit-5-test-annotation)
- [Assert an Exception is Thrown in JUnit 4 and 5](http://www.baeldung.com/junit-assert-exception)
- [@Before vs @BeforeClass vs @BeforeEach vs @BeforeAll](http://www.baeldung.com/junit-before-beforeclass-beforeeach-beforeall)
diff --git a/testing-modules/rest-assured/README.md b/testing-modules/rest-assured/README.md
index de15515f9d..d44fd08335 100644
--- a/testing-modules/rest-assured/README.md
+++ b/testing-modules/rest-assured/README.md
@@ -1,3 +1,4 @@
###Relevant Articles:
- [A Guide to REST-assured](http://www.baeldung.com/rest-assured-tutorial)
- [REST-assured Support for Spring MockMvc](https://www.baeldung.com/spring-mock-mvc-rest-assured)
+- [Getting and Verifying Response Data with REST-assured](https://www.baeldung.com/rest-assured-response)
diff --git a/testing-modules/rest-testing/README.md b/testing-modules/rest-testing/README.md
index 25e036ba5d..2d366bd550 100644
--- a/testing-modules/rest-testing/README.md
+++ b/testing-modules/rest-testing/README.md
@@ -6,9 +6,8 @@
The "REST With Spring" Classes: http://bit.ly/restwithspring
### Relevant Articles:
-- [Test a REST API with Java](http://www.baeldung.com/integration-testing-a-rest-api)
- [Introduction to WireMock](http://www.baeldung.com/introduction-to-wiremock)
-- [Using WireMock Scenarios](http://www.baeldung.com/using-wiremock-scenarios)
+- [Using WireMock Scenarios](https://www.baeldung.com/wiremock-scenarios)
- [REST API Testing with Cucumber](http://www.baeldung.com/cucumber-rest-api-testing)
- [Testing a REST API with JBehave](http://www.baeldung.com/jbehave-rest-testing)
- [REST API Testing with Karate](http://www.baeldung.com/karate-rest-api-testing)
diff --git a/testing-modules/testing/README.md b/testing-modules/testing/README.md
index e96b26ab41..4a7829e867 100644
--- a/testing-modules/testing/README.md
+++ b/testing-modules/testing/README.md
@@ -18,6 +18,6 @@
- [Custom JUnit 4 Test Runners](http://www.baeldung.com/junit-4-custom-runners)
- [Guide to JSpec](http://www.baeldung.com/jspec)
- [Custom Assertions with AssertJ](http://www.baeldung.com/assertj-custom-assertion)
-- [Using Conditions with AssertJ](http://www.baeldung.com/assertj-conditions)
-- [Guide to JavaFaker](https://www.baeldung.com/java-faker)
+- [Using Conditions with AssertJ Assertions](http://www.baeldung.com/assertj-conditions)
+- [A Guide to JavaFaker](https://www.baeldung.com/java-faker)
- [Running JUnit Tests Programmatically, from a Java Application](https://www.baeldung.com/junit-tests-run-programmatically-from-java)