diff --git a/cas/cas-secured-app/README.md b/cas/cas-secured-app/README.md
new file mode 100644
index 0000000000..01c5f91988
--- /dev/null
+++ b/cas/cas-secured-app/README.md
@@ -0,0 +1,2 @@
+## Relevant articles:
+- [CAS SSO With Spring Security](http://www.baeldung.com/spring-security-cas-sso)
diff --git a/core-java-8/README.md b/core-java-8/README.md
index 540a32b0ba..61f8df8f49 100644
--- a/core-java-8/README.md
+++ b/core-java-8/README.md
@@ -32,3 +32,4 @@
- [“Stream has already been operated upon or closed” Exception in Java](http://www.baeldung.com/java-stream-operated-upon-or-closed-exception)
- [Display All Time Zones With GMT And UTC in Java](http://www.baeldung.com/java-time-zones)
- [Copy a File with Java](http://www.baeldung.com/java-copy-file)
+- [Generating Prime Numbers in Java](http://www.baeldung.com/java-generate-prime-numbers)
diff --git a/core-java-9/README.md b/core-java-9/README.md
index 98c855caea..ce8a140dc0 100644
--- a/core-java-9/README.md
+++ b/core-java-9/README.md
@@ -18,3 +18,4 @@
- [How to Get All Dates Between Two Dates?](http://www.baeldung.com/java-between-dates)
- [Java 9 java.util.Objects Additions](http://www.baeldung.com/java-9-objects-new)
- [Compact Strings in Java 9](http://www.baeldung.com/java-9-compact-string)
+- [Convert Date to LocalDate or LocalDateTime and Back](http://www.baeldung.com/java-date-to-localdate-and-localdatetime)
diff --git a/core-java-concurrency/README.md b/core-java-concurrency/README.md
index 48c5f2a50c..23509013d5 100644
--- a/core-java-concurrency/README.md
+++ b/core-java-concurrency/README.md
@@ -31,3 +31,5 @@
- [Overview of the java.util.concurrent](http://www.baeldung.com/java-util-concurrent)
- [Semaphores in Java](http://www.baeldung.com/java-semaphore)
- [Daemon Threads in Java](http://www.baeldung.com/java-daemon-thread)
+- [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)
diff --git a/core-java/README.md b/core-java/README.md
index 8287a21d1e..ae9e0d96c4 100644
--- a/core-java/README.md
+++ b/core-java/README.md
@@ -121,4 +121,8 @@
- [Copy a File with Java](http://www.baeldung.com/java-copy-file)
- [Introduction to Creational Design Patterns](http://www.baeldung.com/creational-design-patterns)
- [Quick Example - Comparator vs Comparable in Java](http://www.baeldung.com/java-comparator-comparable)
-
+- [Quick Guide to Java Stack](http://www.baeldung.com/java-stack)
+- [The Java continue and break Keywords](http://www.baeldung.com/java-continue-and-break)
+- [Java – Append Data to a File](http://www.baeldung.com/java-append-to-file)
+- [Introduction to the Java ArrayDeque](http://www.baeldung.com/java-array-deque)
+- [Guide to java.util.Formatter](http://www.baeldung.com/java-string-formatter)
diff --git a/core-java/src/main/java/com/baeldung/array/SearchArrayTest.java b/core-java/src/main/java/com/baeldung/array/SearchArrayTest.java
index fd11e49373..8b44138b32 100644
--- a/core-java/src/main/java/com/baeldung/array/SearchArrayTest.java
+++ b/core-java/src/main/java/com/baeldung/array/SearchArrayTest.java
@@ -5,12 +5,12 @@ import org.openjdk.jmh.annotations.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
+@BenchmarkMode(Mode.AverageTime)
+@Warmup(iterations = 5)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
public class SearchArrayTest {
@Benchmark
- @BenchmarkMode(Mode.AverageTime)
- @Warmup(iterations = 5)
- @OutputTimeUnit(TimeUnit.MICROSECONDS)
public void searchArrayLoop() {
int count = 1000;
@@ -21,9 +21,6 @@ public class SearchArrayTest {
}
@Benchmark
- @BenchmarkMode(Mode.AverageTime)
- @Warmup(iterations = 5)
- @OutputTimeUnit(TimeUnit.MICROSECONDS)
public void searchArrayAllocNewList() {
int count = 1000;
@@ -35,9 +32,6 @@ public class SearchArrayTest {
}
@Benchmark
- @BenchmarkMode(Mode.AverageTime)
- @Warmup(iterations = 5)
- @OutputTimeUnit(TimeUnit.MICROSECONDS)
public void searchArrayAllocNewSet() {
int count = 1000;
@@ -49,9 +43,6 @@ public class SearchArrayTest {
@Benchmark
- @BenchmarkMode(Mode.AverageTime)
- @Warmup(iterations = 5)
- @OutputTimeUnit(TimeUnit.MICROSECONDS)
public void searchArrayReuseList() {
int count = 1000;
@@ -66,9 +57,6 @@ public class SearchArrayTest {
@Benchmark
- @BenchmarkMode(Mode.AverageTime)
- @Warmup(iterations = 5)
- @OutputTimeUnit(TimeUnit.MICROSECONDS)
public void searchArrayReuseSet() {
int count = 1000;
@@ -81,9 +69,6 @@ public class SearchArrayTest {
@Benchmark
- @BenchmarkMode(Mode.AverageTime)
- @Warmup(iterations = 5)
- @OutputTimeUnit(TimeUnit.MICROSECONDS)
public void searchArrayBinarySearch() {
int count = 1000;
diff --git a/drools/README.MD b/drools/README.MD
index b2259e2878..5efbe0d3c3 100644
--- a/drools/README.MD
+++ b/drools/README.MD
@@ -1,3 +1,4 @@
### Relevant Articles:
- [Introduction to Drools](http://www.baeldung.com/drools)
- [Drools Using Rules from Excel Files](http://www.baeldung.com/drools-excel)
+- [An Example of Backward Chaining in Drools](http://www.baeldung.com/drools-backward-chaining)
diff --git a/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryInitialMigrationTest.java b/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryInitialMigrationIntegrationTest.java
similarity index 92%
rename from flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryInitialMigrationTest.java
rename to flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryInitialMigrationIntegrationTest.java
index b3f2cb29e1..59ef5820d7 100644
--- a/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryInitialMigrationTest.java
+++ b/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryInitialMigrationIntegrationTest.java
@@ -12,7 +12,7 @@ import static org.junit.Assert.assertNotNull;
@RunWith(SpringRunner.class)
@SpringBootTest
-public class CustomerRepositoryInitialMigrationTest {
+public class CustomerRepositoryInitialMigrationIntegrationTest {
@Autowired CustomerRepository customerRepository;
diff --git a/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryInsertDataMigrationTest.java b/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryInsertDataIntegrationTest.java
similarity index 94%
rename from flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryInsertDataMigrationTest.java
rename to flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryInsertDataIntegrationTest.java
index 369e61d98f..3feedf2fd9 100644
--- a/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryInsertDataMigrationTest.java
+++ b/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryInsertDataIntegrationTest.java
@@ -15,7 +15,7 @@ import static org.junit.Assert.*;
@RunWith(SpringRunner.class)
@SpringBootTest
-public class CustomerRepositoryInsertDataMigrationTest {
+public class CustomerRepositoryInsertDataIntegrationTest {
@Autowired CustomerRepository customerRepository;
diff --git a/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryNotNullConstraintMigrationTest.java b/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryNotNullConstraintMigrationIntegrationTest.java
similarity index 91%
rename from flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryNotNullConstraintMigrationTest.java
rename to flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryNotNullConstraintMigrationIntegrationTest.java
index 90517c9225..9ec5d4d77e 100644
--- a/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryNotNullConstraintMigrationTest.java
+++ b/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryNotNullConstraintMigrationIntegrationTest.java
@@ -11,7 +11,7 @@ import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
-public class CustomerRepositoryNotNullConstraintMigrationTest {
+public class CustomerRepositoryNotNullConstraintMigrationIntegrationTest {
@Autowired CustomerRepository customerRepository;
diff --git a/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryUniqueConstraintJavaMigrationTest.java b/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryUniqueConstraintJavaMigrationIntegrationTest.java
similarity index 92%
rename from flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryUniqueConstraintJavaMigrationTest.java
rename to flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryUniqueConstraintJavaMigrationIntegrationTest.java
index e5ba782fda..f615f477bc 100644
--- a/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryUniqueConstraintJavaMigrationTest.java
+++ b/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryUniqueConstraintJavaMigrationIntegrationTest.java
@@ -13,7 +13,7 @@ import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest(properties = {
"flyway.locations[0]=db/migration", "flyway.locations[1]=com/baeldung/springflyway/migration"
})
-public class CustomerRepositoryUniqueConstraintJavaMigrationTest {
+public class CustomerRepositoryUniqueConstraintJavaMigrationIntegrationTest {
@Autowired CustomerRepository customerRepository;
diff --git a/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryUniqueConstraintMigrationTest.java b/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryUniqueConstraintMigrationIntegrationTest.java
similarity index 92%
rename from flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryUniqueConstraintMigrationTest.java
rename to flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryUniqueConstraintMigrationIntegrationTest.java
index 9fa2dee42d..e9ac34b384 100644
--- a/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryUniqueConstraintMigrationTest.java
+++ b/flyway/spring-flyway/src/test/java/com/baeldung/springflyway/CustomerRepositoryUniqueConstraintMigrationIntegrationTest.java
@@ -11,7 +11,7 @@ import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
-public class CustomerRepositoryUniqueConstraintMigrationTest {
+public class CustomerRepositoryUniqueConstraintMigrationIntegrationTest {
@Autowired CustomerRepository customerRepository;
diff --git a/gradle/README.md b/gradle/README.md
index ff12555376..dd5ea03a18 100644
--- a/gradle/README.md
+++ b/gradle/README.md
@@ -1 +1,2 @@
## Relevant articles:
+- [Introduction to Gradle](http://www.baeldung.com/gradle)
diff --git a/hibernate5/README.md b/hibernate5/README.md
index 4690ebbe76..d480a7455c 100644
--- a/hibernate5/README.md
+++ b/hibernate5/README.md
@@ -2,3 +2,5 @@
- [Dynamic Mapping with Hibernate](http://www.baeldung.com/hibernate-dynamic-mapping)
- [An Overview of Identifiers in Hibernate](http://www.baeldung.com/hibernate-identifiers)
+- [Hibernate – Mapping Date and Time](http://www.baeldung.com/hibernate-date-time)
+- [Hibernate Inheritance Mapping](http://www.baeldung.com/hibernate-inheritance)
diff --git a/jsonb/README.md b/jsonb/README.md
index a638f0355c..9293a44808 100644
--- a/jsonb/README.md
+++ b/jsonb/README.md
@@ -1 +1,4 @@
## JSON B
+
+## Relevant articles:
+- [Introduction to the JSON Binding API (JSR 367) in Java](http://www.baeldung.com/java-json-binding-api)
diff --git a/junit5/README.md b/junit5/README.md
new file mode 100644
index 0000000000..fb1685fdd5
--- /dev/null
+++ b/junit5/README.md
@@ -0,0 +1,2 @@
+## Relevant articles:
+- [The Order of Tests in JUnit](http://www.baeldung.com/junit-5-test-order)
diff --git a/libraries/pom.xml b/libraries/pom.xml
index 27d867b68b..eaa2d9d38f 100644
--- a/libraries/pom.xml
+++ b/libraries/pom.xml
@@ -630,13 +630,13 @@
com.google.http-client
google-http-client-jackson2
- ${googleclient.version}
+ ${googleclient.version}
- com.google.http-client
- google-http-client-gson
- ${googleclient.version}
-
+ com.google.http-client
+ google-http-client-gson
+ ${googleclient.version}
+
diff --git a/libraries/src/test/java/com/baeldung/neuroph/XORTest.java b/libraries/src/test/java/com/baeldung/neuroph/XORIntegrationTest.java
similarity index 97%
rename from libraries/src/test/java/com/baeldung/neuroph/XORTest.java
rename to libraries/src/test/java/com/baeldung/neuroph/XORIntegrationTest.java
index 4a6ecf8e46..5da1d166f6 100644
--- a/libraries/src/test/java/com/baeldung/neuroph/XORTest.java
+++ b/libraries/src/test/java/com/baeldung/neuroph/XORIntegrationTest.java
@@ -7,7 +7,7 @@ import org.neuroph.core.NeuralNetwork;
import static org.junit.Assert.*;
-public class XORTest {
+public class XORIntegrationTest {
private NeuralNetwork ann = null;
private void print(String input, double output, double actual) {
diff --git a/osgi/readme.md b/osgi/readme.md
index ea4a411c7b..e380ae06c3 100644
--- a/osgi/readme.md
+++ b/osgi/readme.md
@@ -86,6 +86,9 @@ org.eclipse.osgi_3.12.1.v20170821-1548.jar
= = NOT GOOD = =
+ ## Relevant articles:
+ - [Introduction to OSGi](http://www.baeldung.com/osgi)
+
diff --git a/patterns/README.md b/patterns/README.md
index 67d84154cb..26099ae34f 100644
--- a/patterns/README.md
+++ b/patterns/README.md
@@ -1,4 +1,5 @@
###Relevant Articles:
- [A Guide to the Front Controller Pattern in Java](http://www.baeldung.com/java-front-controller-pattern)
- [Introduction to Intercepting Filter Pattern in Java](http://www.baeldung.com/intercepting-filter-pattern-in-java)
-- [Implementing the Template Method Pattern in Java](http://www.baeldung.com/template-method-pattern-in-java)
+- [Implementing the Template Method Pattern in Java](http://www.baeldung.com/java-template-method-pattern)
+
diff --git a/persistence-modules/spring-jpa/README.md b/persistence-modules/spring-jpa/README.md
index d93271164c..4bfe2a1d25 100644
--- a/persistence-modules/spring-jpa/README.md
+++ b/persistence-modules/spring-jpa/README.md
@@ -15,6 +15,7 @@
- [Deleting Objects with Hibernate](http://www.baeldung.com/delete-with-hibernate)
- [Self-Contained Testing Using an In-Memory Database](http://www.baeldung.com/spring-jpa-test-in-memory-database)
- [Spring Data JPA – Adding a Method in All Repositories](http://www.baeldung.com/spring-data-jpa-method-in-all-repositories)
+- [A Guide to Spring AbstractRoutingDatasource](http://www.baeldung.com/spring-abstract-routing-data-source)
### Eclipse Config
After importing the project into Eclipse, you may see the following error:
diff --git a/pom.xml b/pom.xml
index cf01712cba..2c611e6efe 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,8 +49,6 @@
core-java-8
core-java-concurrency
couchbase
- cas/cas-server
- cas/cas-secured-app
deltaspike
dozer
@@ -141,8 +139,8 @@
persistence-modules/solr
spark-java
+ spring-5-reactive
spring-5-mvc
- spring-acl
spring-activiti
spring-akka
spring-amqp
@@ -152,7 +150,7 @@
spring-batch
spring-bom
spring-boot
- spring-boot-keycloak
+ spring-boot-keycloak
spring-boot-bootstrap
spring-cloud-data-flow
spring-cloud
diff --git a/spring-5-reactive-client/.gitignore b/spring-5-reactive-client/.gitignore
new file mode 100644
index 0000000000..dec013dfa4
--- /dev/null
+++ b/spring-5-reactive-client/.gitignore
@@ -0,0 +1,12 @@
+#folders#
+.idea
+/target
+/neoDb*
+/data
+/src/main/webapp/WEB-INF/classes
+*/META-INF/*
+
+# Packaged files #
+*.jar
+*.war
+*.ear
\ No newline at end of file
diff --git a/spring-5-reactive-client/README.md b/spring-5-reactive-client/README.md
new file mode 100644
index 0000000000..400e343263
--- /dev/null
+++ b/spring-5-reactive-client/README.md
@@ -0,0 +1,15 @@
+## Spring REST Example Project
+
+### The Course
+The "REST With Spring" Classes: http://bit.ly/restwithspring
+
+### Relevant Articles
+
+- [Concurrent Test Execution in Spring 5](http://www.baeldung.com/spring-5-concurrent-tests)
+- [Introduction to the Functional Web Framework in Spring 5](http://www.baeldung.com/spring-5-functional-web)
+- [Exploring the Spring 5 MVC URL Matching Improvements](http://www.baeldung.com/spring-5-mvc-url-matching)
+- [Spring 5 WebClient](http://www.baeldung.com/spring-5-webclient)
+- [Spring 5 Functional Bean Registration](http://www.baeldung.com/spring-5-functional-beans)
+- [The SpringJUnitConfig and SpringJUnitWebConfig Annotations in Spring 5](http://www.baeldung.com/spring-5-junit-config)
+- [Spring Security 5 for Reactive Applications](http://www.baeldung.com/spring-security-5-reactive)
+- [Spring 5 Testing with @EnabledIf Annotation](https://github.com/eugenp/tutorials/tree/master/spring-5)
diff --git a/spring-5-reactive-client/pom.xml b/spring-5-reactive-client/pom.xml
new file mode 100644
index 0000000000..8aa579b724
--- /dev/null
+++ b/spring-5-reactive-client/pom.xml
@@ -0,0 +1,201 @@
+
+
+ 4.0.0
+
+ com.baeldung
+ spring-5-reactive-client
+ 0.0.1-SNAPSHOT
+ jar
+
+ spring-5
+ spring 5 sample project about new features
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.0.0.M7
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+ org.projectreactor
+ reactor-spring
+ ${reactor-spring.version}
+
+
+ javax.json.bind
+ javax.json.bind-api
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.apache.geronimo.specs
+ geronimo-json_1.1_spec
+ ${geronimo-json_1.1_spec.version}
+
+
+ org.apache.johnzon
+ johnzon-jsonb
+
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+
+
+ com.h2database
+ h2
+ runtime
+
+
+
+ org.springframework
+ spring-test
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ org.apache.commons
+ commons-collections4
+ 4.1
+ test
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.junit.platform
+ junit-platform-surefire-provider
+ ${junit.platform.version}
+ test
+
+
+ org.junit.platform
+ junit-platform-runner
+ ${junit.platform.version}
+ test
+
+
+
+ org.projectlombok
+ lombok
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ com.baeldung.Spring5Application
+ JAR
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ 3
+ true
+ methods
+ true
+
+ **/*IntegrationTest.java
+ **/*LiveTest.java
+
+
+
+
+
+
+
+
+ spring-milestones
+ Spring Milestones
+ https://repo.spring.io/milestone
+
+ false
+
+
+
+
+
+ spring-milestones
+ Spring Milestones
+ https://repo.spring.io/milestone
+
+ false
+
+
+
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 1.0.0
+ 5.0.0
+ 2.20
+ 5.0.1.RELEASE
+ 1.0.1.RELEASE
+ 1.1.3
+ 1.0
+ 1.0
+
+
+
diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/reactive/model/Foo.java b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/model/Foo.java
new file mode 100644
index 0000000000..2c49e6146a
--- /dev/null
+++ b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/model/Foo.java
@@ -0,0 +1,13 @@
+package com.baeldung.reactive.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@AllArgsConstructor
+@Data
+public class Foo {
+
+ private long id;
+ private String name;
+
+}
diff --git a/spring-5-reactive-client/src/main/resources/application.properties b/spring-5-reactive-client/src/main/resources/application.properties
new file mode 100644
index 0000000000..2d93456aeb
--- /dev/null
+++ b/spring-5-reactive-client/src/main/resources/application.properties
@@ -0,0 +1,3 @@
+logging.level.root=INFO
+
+server.port=8081
\ No newline at end of file
diff --git a/spring-5-reactive-client/src/main/resources/logback.xml b/spring-5-reactive-client/src/main/resources/logback.xml
new file mode 100644
index 0000000000..8bbe8c1d67
--- /dev/null
+++ b/spring-5-reactive-client/src/main/resources/logback.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ # Pattern of log message for console appender
+ %d{yyyy-MM-dd HH:mm:ss} %-5p %m%n
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-5-reactive-client/src/main/webapp/WEB-INF/web.xml b/spring-5-reactive-client/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000000..bfcf43dad2
--- /dev/null
+++ b/spring-5-reactive-client/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,21 @@
+
+
+
+ Spring Functional Application
+
+
+ functional
+ com.baeldung.functional.RootServlet
+ 1
+ true
+
+
+ functional
+ /
+
+
+
+
\ No newline at end of file
diff --git a/spring-5-reactive-client/src/test/java/com/baeldung/reactive/ReactiveIntegrationTest.java b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/ReactiveIntegrationTest.java
new file mode 100644
index 0000000000..394ff42e5f
--- /dev/null
+++ b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/ReactiveIntegrationTest.java
@@ -0,0 +1,42 @@
+package com.baeldung.reactive;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.web.reactive.function.client.ClientResponse;
+import org.springframework.web.reactive.function.client.WebClient;
+
+import com.baeldung.reactive.model.Foo;
+
+import reactor.core.publisher.Mono;
+
+@SpringBootTest
+public class ReactiveIntegrationTest {
+
+ private WebClient client;
+
+ @BeforeEach
+ public void before() {
+ client = WebClient.create("http://localhost:8080");
+ }
+
+ //
+
+ @Test
+ public void whenMonoReactiveEndpointIsConsumed_thenCorrectOutput() {
+ final Mono fooMono = client.get().uri("/foos/123").exchange().log();
+
+ System.out.println(fooMono.subscribe());
+ }
+
+ @Test
+ public void whenFluxReactiveEndpointIsConsumed_thenCorrectOutput() throws InterruptedException {
+ client.get().uri("/foos")
+ .retrieve()
+ .bodyToFlux(Foo.class).log()
+ .subscribe(System.out::println);
+
+ System.out.println();
+ }
+
+}
diff --git a/spring-5-reactive-client/src/test/java/com/baeldung/reactive/Spring5ReactiveTestApplication.java b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/Spring5ReactiveTestApplication.java
new file mode 100644
index 0000000000..c884ace323
--- /dev/null
+++ b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/Spring5ReactiveTestApplication.java
@@ -0,0 +1,35 @@
+package com.baeldung.reactive;
+
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.reactive.function.client.WebClient;
+
+import com.baeldung.reactive.model.Foo;
+
+@SpringBootApplication
+public class Spring5ReactiveTestApplication {
+
+ @Bean
+ public WebClient client() {
+ return WebClient.create("http://localhost:8080");
+ }
+
+ @Bean
+ CommandLineRunner cmd(WebClient client) {
+ return args -> {
+ client.get().uri("/foos2")
+ .retrieve()
+ .bodyToFlux(Foo.class).log()
+ .subscribe(System.out::println);
+ };
+ }
+
+ //
+
+ public static void main(String[] args) {
+ SpringApplication.run(Spring5ReactiveTestApplication.class, args);
+ }
+
+}
diff --git a/spring-5-reactive-client/src/test/resources/logback-test.xml b/spring-5-reactive-client/src/test/resources/logback-test.xml
new file mode 100644
index 0000000000..8bbe8c1d67
--- /dev/null
+++ b/spring-5-reactive-client/src/test/resources/logback-test.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ # Pattern of log message for console appender
+ %d{yyyy-MM-dd HH:mm:ss} %-5p %m%n
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-5-reactive/.gitignore b/spring-5-reactive/.gitignore
new file mode 100644
index 0000000000..dec013dfa4
--- /dev/null
+++ b/spring-5-reactive/.gitignore
@@ -0,0 +1,12 @@
+#folders#
+.idea
+/target
+/neoDb*
+/data
+/src/main/webapp/WEB-INF/classes
+*/META-INF/*
+
+# Packaged files #
+*.jar
+*.war
+*.ear
\ No newline at end of file
diff --git a/spring-5-reactive/README.md b/spring-5-reactive/README.md
new file mode 100644
index 0000000000..400e343263
--- /dev/null
+++ b/spring-5-reactive/README.md
@@ -0,0 +1,15 @@
+## Spring REST Example Project
+
+### The Course
+The "REST With Spring" Classes: http://bit.ly/restwithspring
+
+### Relevant Articles
+
+- [Concurrent Test Execution in Spring 5](http://www.baeldung.com/spring-5-concurrent-tests)
+- [Introduction to the Functional Web Framework in Spring 5](http://www.baeldung.com/spring-5-functional-web)
+- [Exploring the Spring 5 MVC URL Matching Improvements](http://www.baeldung.com/spring-5-mvc-url-matching)
+- [Spring 5 WebClient](http://www.baeldung.com/spring-5-webclient)
+- [Spring 5 Functional Bean Registration](http://www.baeldung.com/spring-5-functional-beans)
+- [The SpringJUnitConfig and SpringJUnitWebConfig Annotations in Spring 5](http://www.baeldung.com/spring-5-junit-config)
+- [Spring Security 5 for Reactive Applications](http://www.baeldung.com/spring-security-5-reactive)
+- [Spring 5 Testing with @EnabledIf Annotation](https://github.com/eugenp/tutorials/tree/master/spring-5)
diff --git a/spring-5-reactive/pom.xml b/spring-5-reactive/pom.xml
new file mode 100644
index 0000000000..c1c18fbc82
--- /dev/null
+++ b/spring-5-reactive/pom.xml
@@ -0,0 +1,201 @@
+
+
+ 4.0.0
+
+ com.baeldung
+ spring-5-reactive
+ 0.0.1-SNAPSHOT
+ jar
+
+ spring-5
+ spring 5 sample project about new features
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.0.0.M7
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+ org.projectreactor
+ reactor-spring
+ ${reactor-spring.version}
+
+
+ javax.json.bind
+ javax.json.bind-api
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.apache.geronimo.specs
+ geronimo-json_1.1_spec
+ ${geronimo-json_1.1_spec.version}
+
+
+ org.apache.johnzon
+ johnzon-jsonb
+
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+
+
+ com.h2database
+ h2
+ runtime
+
+
+
+ org.springframework
+ spring-test
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ org.apache.commons
+ commons-collections4
+ 4.1
+ test
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.junit.platform
+ junit-platform-surefire-provider
+ ${junit.platform.version}
+ test
+
+
+ org.junit.platform
+ junit-platform-runner
+ ${junit.platform.version}
+ test
+
+
+
+ org.projectlombok
+ lombok
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ com.baeldung.Spring5Application
+ JAR
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ 3
+ true
+ methods
+ true
+
+ **/*IntegrationTest.java
+ **/*LiveTest.java
+
+
+
+
+
+
+
+
+ spring-milestones
+ Spring Milestones
+ https://repo.spring.io/milestone
+
+ false
+
+
+
+
+
+ spring-milestones
+ Spring Milestones
+ https://repo.spring.io/milestone
+
+ false
+
+
+
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 1.0.0
+ 5.0.0
+ 2.20
+ 5.0.1.RELEASE
+ 1.0.1.RELEASE
+ 1.1.3
+ 1.0
+ 1.0
+
+
+
diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/Spring5ReactiveApplication.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/Spring5ReactiveApplication.java
new file mode 100644
index 0000000000..a9308124fa
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/Spring5ReactiveApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.reactive;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Spring5ReactiveApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Spring5ReactiveApplication.class, args);
+ }
+
+}
diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/FooReactiveController.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/FooReactiveController.java
new file mode 100644
index 0000000000..933d469f65
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/controller/FooReactiveController.java
@@ -0,0 +1,46 @@
+package com.baeldung.reactive.controller;
+
+import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
+
+import java.time.Duration;
+import java.util.Random;
+import java.util.stream.Stream;
+
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baeldung.reactive.model.Foo;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.util.function.Tuple2;
+
+@RestController
+public class FooReactiveController {
+
+ @GetMapping("/foos/{id}")
+ public Mono getFoo(@PathVariable("id") long id) {
+ return Mono.just(new Foo(id, randomAlphabetic(6)));
+ }
+
+ @GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE, value = "/foos")
+ public Flux getAllFoos2() {
+ final Flux foosFlux = Flux.fromStream(Stream.generate(() -> new Foo(new Random().nextLong(), randomAlphabetic(6))));
+ final Flux emmitFlux = Flux.interval(Duration.ofSeconds(1));
+ return Flux.zip(foosFlux, emmitFlux).map(Tuple2::getT1);
+ }
+
+ @GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE, value = "/foos2")
+ public Flux getAllFoos() {
+ final Flux flux = Flux. create(fluxSink -> {
+ while (true) {
+ fluxSink.next(new Foo(new Random().nextLong(), randomAlphabetic(6)));
+ }
+ }).sample(Duration.ofSeconds(1)).log();
+
+ return flux;
+ }
+
+}
diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/model/Foo.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/model/Foo.java
new file mode 100644
index 0000000000..2c49e6146a
--- /dev/null
+++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/model/Foo.java
@@ -0,0 +1,13 @@
+package com.baeldung.reactive.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@AllArgsConstructor
+@Data
+public class Foo {
+
+ private long id;
+ private String name;
+
+}
diff --git a/spring-5-reactive/src/main/resources/application.properties b/spring-5-reactive/src/main/resources/application.properties
new file mode 100644
index 0000000000..4b49e8e8a2
--- /dev/null
+++ b/spring-5-reactive/src/main/resources/application.properties
@@ -0,0 +1 @@
+logging.level.root=INFO
\ No newline at end of file
diff --git a/spring-5-reactive/src/main/webapp/WEB-INF/web.xml b/spring-5-reactive/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000000..bfcf43dad2
--- /dev/null
+++ b/spring-5-reactive/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,21 @@
+
+
+
+ Spring Functional Application
+
+
+ functional
+ com.baeldung.functional.RootServlet
+ 1
+ true
+
+
+ functional
+ /
+
+
+
+
\ No newline at end of file
diff --git a/spring-5-reactive/src/test/java/com/baeldung/reactive/FluxUnitTest.java b/spring-5-reactive/src/test/java/com/baeldung/reactive/FluxUnitTest.java
new file mode 100644
index 0000000000..bad5fc5f22
--- /dev/null
+++ b/spring-5-reactive/src/test/java/com/baeldung/reactive/FluxUnitTest.java
@@ -0,0 +1,30 @@
+package com.baeldung.reactive;
+
+import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
+import static org.junit.Assert.assertNotNull;
+
+import java.time.Duration;
+import java.util.Random;
+
+import org.junit.jupiter.api.Test;
+
+import com.baeldung.reactive.model.Foo;
+
+import reactor.core.publisher.Flux;
+
+public class FluxUnitTest {
+
+ @Test
+ public void whenFluxIsConstructed_thenCorrect() {
+ final Flux flux = Flux. create(fluxSink -> {
+ while (true) {
+ fluxSink.next(new Foo(new Random().nextLong(), randomAlphabetic(6)));
+ }
+ }).sample(Duration.ofSeconds(1)).log();
+
+ flux.subscribe();
+
+ assertNotNull(flux);
+ }
+
+}
diff --git a/spring-5/README.md b/spring-5/README.md
index 1b65d01811..400e343263 100644
--- a/spring-5/README.md
+++ b/spring-5/README.md
@@ -11,3 +11,5 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Spring 5 WebClient](http://www.baeldung.com/spring-5-webclient)
- [Spring 5 Functional Bean Registration](http://www.baeldung.com/spring-5-functional-beans)
- [The SpringJUnitConfig and SpringJUnitWebConfig Annotations in Spring 5](http://www.baeldung.com/spring-5-junit-config)
+- [Spring Security 5 for Reactive Applications](http://www.baeldung.com/spring-security-5-reactive)
+- [Spring 5 Testing with @EnabledIf Annotation](https://github.com/eugenp/tutorials/tree/master/spring-5)
diff --git a/spring-5/src/main/java/com/baeldung/web/PathPatternController.java b/spring-5/src/main/java/com/baeldung/web/PathPatternController.java
index 15b689257a..6fd972f2a4 100644
--- a/spring-5/src/main/java/com/baeldung/web/PathPatternController.java
+++ b/spring-5/src/main/java/com/baeldung/web/PathPatternController.java
@@ -2,7 +2,6 @@ package com.baeldung.web;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
diff --git a/spring-acl/pom.xml b/spring-acl/pom.xml
deleted file mode 100644
index 3bcc0cf596..0000000000
--- a/spring-acl/pom.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
- 4.0.0
-
- com.baeldung
- spring-acl
- 0.0.1-SNAPSHOT
- war
-
- spring-acl
- Spring ACL
-
-
- parent-boot-5
- com.baeldung
- 0.0.1-SNAPSHOT
- ../parent-boot-5
-
-
-
-
-
- org.springframework.boot
- spring-boot-starter-data-jpa
-
-
-
- com.h2database
- h2
-
-
-
- org.springframework
- spring-test
- test
-
-
-
- org.springframework.security
- spring-security-test
- test
-
-
-
- org.springframework.security
- spring-security-acl
-
-
- org.springframework.security
- spring-security-config
-
-
- org.springframework
- spring-context-support
-
-
- net.sf.ehcache
- ehcache-core
- 2.6.11
- jar
-
-
-
-
-
diff --git a/spring-acl/src/main/java/org/baeldung/acl/config/ACLContext.java b/spring-acl/src/main/java/org/baeldung/acl/config/ACLContext.java
deleted file mode 100644
index 63a4ea58ef..0000000000
--- a/spring-acl/src/main/java/org/baeldung/acl/config/ACLContext.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package org.baeldung.acl.config;
-
-import javax.sql.DataSource;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.cache.ehcache.EhCacheFactoryBean;
-import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
-import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
-import org.springframework.security.acls.AclPermissionCacheOptimizer;
-import org.springframework.security.acls.AclPermissionEvaluator;
-import org.springframework.security.acls.domain.AclAuthorizationStrategy;
-import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
-import org.springframework.security.acls.domain.ConsoleAuditLogger;
-import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
-import org.springframework.security.acls.domain.EhCacheBasedAclCache;
-import org.springframework.security.acls.jdbc.BasicLookupStrategy;
-import org.springframework.security.acls.jdbc.JdbcMutableAclService;
-import org.springframework.security.acls.jdbc.LookupStrategy;
-import org.springframework.security.acls.model.PermissionGrantingStrategy;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-
-@Configuration
-@EnableAutoConfiguration
-public class ACLContext {
-
- @Autowired
- DataSource dataSource;
-
- @Bean
- public EhCacheBasedAclCache aclCache() {
- return new EhCacheBasedAclCache(aclEhCacheFactoryBean().getObject(), permissionGrantingStrategy(), aclAuthorizationStrategy());
- }
-
- @Bean
- public EhCacheFactoryBean aclEhCacheFactoryBean() {
- EhCacheFactoryBean ehCacheFactoryBean = new EhCacheFactoryBean();
- ehCacheFactoryBean.setCacheManager(aclCacheManager().getObject());
- ehCacheFactoryBean.setCacheName("aclCache");
- return ehCacheFactoryBean;
- }
-
- @Bean
- public EhCacheManagerFactoryBean aclCacheManager() {
- return new EhCacheManagerFactoryBean();
- }
-
- @Bean
- public PermissionGrantingStrategy permissionGrantingStrategy() {
- return new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger());
- }
-
- @Bean
- public AclAuthorizationStrategy aclAuthorizationStrategy() {
- return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ADMIN"));
- }
-
- @Bean
- public MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler() {
- DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
- AclPermissionEvaluator permissionEvaluator = new AclPermissionEvaluator(aclService());
- expressionHandler.setPermissionEvaluator(permissionEvaluator);
- expressionHandler.setPermissionCacheOptimizer(new AclPermissionCacheOptimizer(aclService()));
- return expressionHandler;
- }
-
- @Bean
- public LookupStrategy lookupStrategy() {
- return new BasicLookupStrategy(dataSource, aclCache(), aclAuthorizationStrategy(), new ConsoleAuditLogger());
- }
-
- @Bean
- public JdbcMutableAclService aclService() {
- return new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
- }
-
-}
\ No newline at end of file
diff --git a/spring-acl/src/main/java/org/baeldung/acl/config/AclMethodSecurityConfiguration.java b/spring-acl/src/main/java/org/baeldung/acl/config/AclMethodSecurityConfiguration.java
deleted file mode 100644
index 110c4a6d24..0000000000
--- a/spring-acl/src/main/java/org/baeldung/acl/config/AclMethodSecurityConfiguration.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.baeldung.acl.config;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
-import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
-import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
-
-@Configuration
-@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
-public class AclMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
-
- @Autowired
- MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler;
-
- @Override
- protected MethodSecurityExpressionHandler createExpressionHandler() {
- return defaultMethodSecurityExpressionHandler;
- }
-
-}
diff --git a/spring-acl/src/main/java/org/baeldung/acl/config/JPAPersistenceConfig.java b/spring-acl/src/main/java/org/baeldung/acl/config/JPAPersistenceConfig.java
deleted file mode 100644
index 9b87efa92c..0000000000
--- a/spring-acl/src/main/java/org/baeldung/acl/config/JPAPersistenceConfig.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.baeldung.acl.config;
-
-import org.springframework.boot.autoconfigure.domain.EntityScan;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.PropertySource;
-import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
-import org.springframework.transaction.annotation.EnableTransactionManagement;
-
-@Configuration
-@EnableTransactionManagement
-@EnableJpaRepositories(basePackages = "org.baeldung.acl.persistence.dao")
-@PropertySource("classpath:org.baeldung.acl.datasource.properties")
-@EntityScan(basePackages={ "org.baeldung.acl.persistence.entity" })
-public class JPAPersistenceConfig {
-
-}
diff --git a/spring-acl/src/main/java/org/baeldung/acl/persistence/dao/NoticeMessageRepository.java b/spring-acl/src/main/java/org/baeldung/acl/persistence/dao/NoticeMessageRepository.java
deleted file mode 100644
index 8662c88d6c..0000000000
--- a/spring-acl/src/main/java/org/baeldung/acl/persistence/dao/NoticeMessageRepository.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.baeldung.acl.persistence.dao;
-
-import java.util.List;
-
-import org.baeldung.acl.persistence.entity.NoticeMessage;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.repository.query.Param;
-import org.springframework.security.access.prepost.PostAuthorize;
-import org.springframework.security.access.prepost.PostFilter;
-import org.springframework.security.access.prepost.PreAuthorize;
-
-public interface NoticeMessageRepository extends JpaRepository{
-
- @PostFilter("hasPermission(filterObject, 'READ')")
- List findAll();
-
- @PostAuthorize("hasPermission(returnObject, 'READ')")
- NoticeMessage findById(Integer id);
-
- @SuppressWarnings("unchecked")
- @PreAuthorize("hasPermission(#noticeMessage, 'WRITE')")
- NoticeMessage save(@Param("noticeMessage")NoticeMessage noticeMessage);
-
-}
diff --git a/spring-acl/src/main/java/org/baeldung/acl/persistence/entity/NoticeMessage.java b/spring-acl/src/main/java/org/baeldung/acl/persistence/entity/NoticeMessage.java
deleted file mode 100644
index 23f01a8edb..0000000000
--- a/spring-acl/src/main/java/org/baeldung/acl/persistence/entity/NoticeMessage.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.baeldung.acl.persistence.entity;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.Table;
-
-@Entity
-@Table(name="system_message")
-public class NoticeMessage {
-
- @Id
- @Column
- private Integer id;
- @Column
- private String content;
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getContent() {
- return content;
- }
- public void setContent(String content) {
- this.content = content;
- }
-}
\ No newline at end of file
diff --git a/spring-acl/src/main/resources/acl-data.sql b/spring-acl/src/main/resources/acl-data.sql
deleted file mode 100644
index 6c01eaacc2..0000000000
--- a/spring-acl/src/main/resources/acl-data.sql
+++ /dev/null
@@ -1,28 +0,0 @@
-INSERT INTO system_message(id,content) VALUES (1,'First Level Message');
-INSERT INTO system_message(id,content) VALUES (2,'Second Level Message');
-INSERT INTO system_message(id,content) VALUES (3,'Third Level Message');
-
-INSERT INTO acl_class (id, class) VALUES
-(1, 'org.baeldung.acl.persistence.entity.NoticeMessage');
-
-INSERT INTO acl_sid (id, principal, sid) VALUES
-(1, 1, 'manager'),
-(2, 1, 'hr'),
-(3, 1, 'admin'),
-(4, 0, 'ROLE_EDITOR');
-
-INSERT INTO acl_object_identity (id, object_id_class, object_id_identity, parent_object, owner_sid, entries_inheriting) VALUES
-(1, 1, 1, NULL, 3, 0),
-(2, 1, 2, NULL, 3, 0),
-(3, 1, 3, NULL, 3, 0)
-;
-
-INSERT INTO acl_entry (id, acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure) VALUES
-(1, 1, 1, 1, 1, 1, 1, 1),
-(2, 1, 2, 1, 2, 1, 1, 1),
-(3, 1, 3, 4, 1, 1, 1, 1),
-(4, 2, 1, 2, 1, 1, 1, 1),
-(5, 2, 2, 4, 1, 1, 1, 1),
-(6, 3, 1, 4, 1, 1, 1, 1),
-(7, 3, 2, 4, 2, 1, 1, 1)
-;
\ No newline at end of file
diff --git a/spring-acl/src/main/resources/acl-schema.sql b/spring-acl/src/main/resources/acl-schema.sql
deleted file mode 100644
index 58e9394b2b..0000000000
--- a/spring-acl/src/main/resources/acl-schema.sql
+++ /dev/null
@@ -1,58 +0,0 @@
-create table system_message (id integer not null, content varchar(255), primary key (id));
-
-CREATE TABLE IF NOT EXISTS acl_sid (
- id bigint(20) NOT NULL AUTO_INCREMENT,
- principal tinyint(1) NOT NULL,
- sid varchar(100) NOT NULL,
- PRIMARY KEY (id),
- UNIQUE KEY unique_uk_1 (sid,principal)
-);
-
-CREATE TABLE IF NOT EXISTS acl_class (
- id bigint(20) NOT NULL AUTO_INCREMENT,
- class varchar(255) NOT NULL,
- PRIMARY KEY (id),
- UNIQUE KEY unique_uk_2 (class)
-);
-
-CREATE TABLE IF NOT EXISTS acl_entry (
- id bigint(20) NOT NULL AUTO_INCREMENT,
- acl_object_identity bigint(20) NOT NULL,
- ace_order int(11) NOT NULL,
- sid bigint(20) NOT NULL,
- mask int(11) NOT NULL,
- granting tinyint(1) NOT NULL,
- audit_success tinyint(1) NOT NULL,
- audit_failure tinyint(1) NOT NULL,
- PRIMARY KEY (id),
- UNIQUE KEY unique_uk_4 (acl_object_identity,ace_order)
-);
-
-CREATE TABLE IF NOT EXISTS acl_object_identity (
- id bigint(20) NOT NULL AUTO_INCREMENT,
- object_id_class bigint(20) NOT NULL,
- object_id_identity bigint(20) NOT NULL,
- parent_object bigint(20) DEFAULT NULL,
- owner_sid bigint(20) DEFAULT NULL,
- entries_inheriting tinyint(1) NOT NULL,
- PRIMARY KEY (id),
- UNIQUE KEY unique_uk_3 (object_id_class,object_id_identity)
-);
-
-ALTER TABLE acl_entry
-ADD FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity(id);
-
-ALTER TABLE acl_entry
-ADD FOREIGN KEY (sid) REFERENCES acl_sid(id);
-
---
--- Constraints for table acl_object_identity
---
-ALTER TABLE acl_object_identity
-ADD FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id);
-
-ALTER TABLE acl_object_identity
-ADD FOREIGN KEY (object_id_class) REFERENCES acl_class (id);
-
-ALTER TABLE acl_object_identity
-ADD FOREIGN KEY (owner_sid) REFERENCES acl_sid (id);
\ No newline at end of file
diff --git a/spring-acl/src/main/resources/org.baeldung.acl.datasource.properties b/spring-acl/src/main/resources/org.baeldung.acl.datasource.properties
deleted file mode 100644
index 739dd3f07c..0000000000
--- a/spring-acl/src/main/resources/org.baeldung.acl.datasource.properties
+++ /dev/null
@@ -1,12 +0,0 @@
-spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE
-spring.datasource.username=sa
-spring.datasource.password=
-spring.datasource.driverClassName=org.h2.Driver
-spring.jpa.hibernate.ddl-auto=update
-spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
-
-spring.h2.console.path=/myconsole
-spring.h2.console.enabled=true
-spring.datasource.initialize=true
-spring.datasource.schema=classpath:acl-schema.sql
-spring.datasource.data=classpath:acl-data.sql
\ No newline at end of file
diff --git a/spring-acl/src/test/java/org/baeldung/acl/SpringAclTest.java b/spring-acl/src/test/java/org/baeldung/acl/SpringAclTest.java
deleted file mode 100644
index fd9069d9bc..0000000000
--- a/spring-acl/src/test/java/org/baeldung/acl/SpringAclTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package org.baeldung.acl;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import java.util.List;
-
-import org.baeldung.acl.persistence.dao.NoticeMessageRepository;
-import org.baeldung.acl.persistence.entity.NoticeMessage;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.access.AccessDeniedException;
-import org.springframework.security.test.context.support.WithMockUser;
-import org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.TestExecutionListeners;
-import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
-import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
-import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
-import org.springframework.test.context.web.ServletTestExecutionListener;
-
-@RunWith(SpringJUnit4ClassRunner.class)
-@ContextConfiguration
-@TestExecutionListeners(listeners={ServletTestExecutionListener.class,
- DependencyInjectionTestExecutionListener.class,
- DirtiesContextTestExecutionListener.class,
- TransactionalTestExecutionListener.class,
- WithSecurityContextTestExecutionListener.class})
-public class SpringAclTest extends AbstractJUnit4SpringContextTests{
-
- private static Integer FIRST_MESSAGE_ID = 1;
- private static Integer SECOND_MESSAGE_ID = 2;
- private static Integer THIRD_MESSAGE_ID = 3;
- private static String EDITTED_CONTENT = "EDITED";
-
- @Configuration
- @ComponentScan("org.baeldung.acl.*")
- public static class SpringConfig {
-
- }
-
- @Autowired
- NoticeMessageRepository repo;
-
- @Test
- @WithMockUser(username="manager")
- public void givenUsernameManager_whenFindAllMessage_thenReturnFirstMessage(){
- List details = repo.findAll();
- assertNotNull(details);
- assertEquals(1,details.size());
- assertEquals(FIRST_MESSAGE_ID,details.get(0).getId());
- }
-
- @Test
- @WithMockUser(username="manager")
- public void givenUsernameManager_whenFindFirstMessageByIdAndUpdateFirstMessageContent_thenOK(){
- NoticeMessage firstMessage = repo.findById(FIRST_MESSAGE_ID);
- assertNotNull(firstMessage);
- assertEquals(FIRST_MESSAGE_ID,firstMessage.getId());
-
- firstMessage.setContent(EDITTED_CONTENT);
- repo.save(firstMessage);
-
- NoticeMessage editedFirstMessage = repo.findById(FIRST_MESSAGE_ID);
- assertNotNull(editedFirstMessage);
- assertEquals(FIRST_MESSAGE_ID,editedFirstMessage.getId());
- assertEquals(EDITTED_CONTENT,editedFirstMessage.getContent());
- }
-
- @Test
- @WithMockUser(username="hr")
- public void givenUsernameHr_whenFindMessageById2_thenOK(){
- NoticeMessage secondMessage = repo.findById(SECOND_MESSAGE_ID);
- assertNotNull(secondMessage);
- assertEquals(SECOND_MESSAGE_ID,secondMessage.getId());
- }
-
- @Test(expected=AccessDeniedException.class)
- @WithMockUser(username="hr")
- public void givenUsernameHr_whenUpdateMessageWithId2_thenFail(){
- NoticeMessage secondMessage = new NoticeMessage();
- secondMessage.setId(SECOND_MESSAGE_ID);
- secondMessage.setContent(EDITTED_CONTENT);
- repo.save(secondMessage);
- }
-
- @Test
- @WithMockUser(roles={"EDITOR"})
- public void givenRoleEditor_whenFindAllMessage_thenReturnThreeMessage(){
- List details = repo.findAll();
- assertNotNull(details);
- assertEquals(3,details.size());
- }
-
- @Test
- @WithMockUser(roles={"EDITOR"})
- public void givenRoleEditor_whenUpdateThirdMessage_thenOK(){
- NoticeMessage thirdMessage = new NoticeMessage();
- thirdMessage.setId(THIRD_MESSAGE_ID);
- thirdMessage.setContent(EDITTED_CONTENT);
- repo.save(thirdMessage);
- }
-
- @Test(expected=AccessDeniedException.class)
- @WithMockUser(roles={"EDITOR"})
- public void givenRoleEditor_whenFindFirstMessageByIdAndUpdateFirstMessageContent_thenFail(){
- NoticeMessage firstMessage = repo.findById(FIRST_MESSAGE_ID);
- assertNotNull(firstMessage);
- assertEquals(FIRST_MESSAGE_ID,firstMessage.getId());
- firstMessage.setContent(EDITTED_CONTENT);
- repo.save(firstMessage);
- }
-}
-
\ No newline at end of file
diff --git a/spring-aop/README.md b/spring-aop/README.md
index 03d5d8f429..af8ab71da0 100644
--- a/spring-aop/README.md
+++ b/spring-aop/README.md
@@ -2,4 +2,5 @@
- [Implementing a Custom Spring AOP Annotation](http://www.baeldung.com/spring-aop-annotation)
- [Intro to AspectJ](http://www.baeldung.com/aspectj)
-- [Spring Performance Logging](http://www.baeldung.com/spring-performance-logging)
\ No newline at end of file
+- [Spring Performance Logging](http://www.baeldung.com/spring-performance-logging)
+- [Introduction to Spring AOP](http://www.baeldung.com/spring-aop)
diff --git a/spring-boot-keycloak/README.md b/spring-boot-keycloak/README.md
new file mode 100644
index 0000000000..cfe82c6cf7
--- /dev/null
+++ b/spring-boot-keycloak/README.md
@@ -0,0 +1,2 @@
+## Relevant articles:
+- [A Quick Guide to Using Keycloak with Spring Boot](http://www.baeldung.com/spring-boot-keycloak)
diff --git a/spring-boot/README.MD b/spring-boot/README.MD
index f126df00af..7b5fb3c880 100644
--- a/spring-boot/README.MD
+++ b/spring-boot/README.MD
@@ -28,4 +28,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [Spring Boot and Togglz Aspect](http://www.baeldung.com/spring-togglz)
- [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)
-
+- [Quick Guide on data.sql and schema.sql Files in Spring Boot](http://www.baeldung.com/spring-boot-data-sql-and-schema-sql)
diff --git a/spring-cloud-cli/README.md b/spring-cloud-cli/README.md
index 5f83ab06fa..7f29be3f07 100644
--- a/spring-cloud-cli/README.md
+++ b/spring-cloud-cli/README.md
@@ -3,4 +3,4 @@
## Spring Cloud CLI
### Relevant Articles:
-- [Introduction to Spring Cloud CLI](http://www.baeldung.com/introduction-to-spring-cloud-cli/)
\ No newline at end of file
+- [Introduction to Spring Cloud CLI](http://www.baeldung.com/spring-cloud-cli)
diff --git a/spring-core/README.md b/spring-core/README.md
index 81a7aaa952..dc3bb1c9f0 100644
--- a/spring-core/README.md
+++ b/spring-core/README.md
@@ -8,3 +8,5 @@
- [Spring YAML Configuration](http://www.baeldung.com/spring-yaml)
- [Introduction to Spring’s StreamUtils](http://www.baeldung.com/spring-stream-utils)
- [Using Spring @Value with Defaults](http://www.baeldung.com/spring-value-defaults)
+- [Groovy Bean Definitions](http://www.baeldung.com/spring-groovy-beans)
+- [XML-Based Injection in Spring](http://www.baeldung.com/spring-xml-injection)
diff --git a/spring-hibernate3/README.md b/spring-hibernate3/README.md
new file mode 100644
index 0000000000..02928dfb51
--- /dev/null
+++ b/spring-hibernate3/README.md
@@ -0,0 +1,2 @@
+## Relevant articles:
+- [HibernateException: No Hibernate Session Bound to Thread in Hibernate 3](http://www.baeldung.com/no-hibernate-session-bound-to-thread-exception)
diff --git a/spring-rest-simple/pom.xml b/spring-rest-simple/pom.xml
index f3fdd78ff4..7314785731 100644
--- a/spring-rest-simple/pom.xml
+++ b/spring-rest-simple/pom.xml
@@ -346,7 +346,7 @@
- 1.3.2
+ 1.3.3
4.0.0
1.4
3.1.0
diff --git a/spring-rest-simple/src/main/java/com/baeldung/apachefileupload/UploadController.java b/spring-rest-simple/src/main/java/com/baeldung/apachefileupload/UploadController.java
new file mode 100644
index 0000000000..b9b6739898
--- /dev/null
+++ b/spring-rest-simple/src/main/java/com/baeldung/apachefileupload/UploadController.java
@@ -0,0 +1,73 @@
+package com.baeldung.apachefileupload;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.FileItemIterator;
+import org.apache.commons.fileupload.FileItemStream;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.apache.commons.fileupload.util.Streams;
+import org.apache.commons.io.IOUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class UploadController {
+
+ @RequestMapping(value = "/upload", method = RequestMethod.POST)
+ public String handleUpload(HttpServletRequest request) {
+ System.out.println(System.getProperty("java.io.tmpdir"));
+ boolean isMultipart = ServletFileUpload.isMultipartContent(request);
+ // Create a factory for disk-based file items
+ DiskFileItemFactory factory = new DiskFileItemFactory();
+ factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
+ factory.setSizeThreshold(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD);
+ factory.setFileCleaningTracker(null);
+ // Configure a repository (to ensure a secure temp location is used)
+ ServletFileUpload upload = new ServletFileUpload(factory);
+ try {
+ // Parse the request
+ List items = upload.parseRequest(request);
+ // Process the uploaded items
+ Iterator iter = items.iterator();
+ while (iter.hasNext()) {
+ FileItem item = iter.next();
+
+ if (!item.isFormField()) {
+ try (InputStream uploadedStream = item.getInputStream();
+ OutputStream out = new FileOutputStream("file.mov");) {
+ IOUtils.copy(uploadedStream, out);
+ out.close();
+ }
+ }
+ }
+ // Parse the request with Streaming API
+ upload = new ServletFileUpload();
+ FileItemIterator iterStream = upload.getItemIterator(request);
+ while (iterStream.hasNext()) {
+ FileItemStream item = iterStream.next();
+ String name = item.getFieldName();
+ InputStream stream = item.openStream();
+ if (!item.isFormField()) {
+ //Process the InputStream
+ } else {
+ //process form fields
+ String formFieldValue = Streams.asString(stream);
+ }
+ }
+ return "success!";
+ } catch (IOException | FileUploadException ex) {
+ return "failed: " + ex.getMessage();
+ }
+ }
+
+}
diff --git a/spring-security-acl/pom.xml b/spring-security-acl/pom.xml
index 67197bc2f8..a19a54dd88 100644
--- a/spring-security-acl/pom.xml
+++ b/spring-security-acl/pom.xml
@@ -3,7 +3,6 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- com.baeldung
spring-security-acl
0.0.1-SNAPSHOT
war
diff --git a/spring-security-acl/src/main/java/org/baeldung/acl/Application.java b/spring-security-acl/src/main/java/org/baeldung/acl/Application.java
new file mode 100644
index 0000000000..665ca64076
--- /dev/null
+++ b/spring-security-acl/src/main/java/org/baeldung/acl/Application.java
@@ -0,0 +1,11 @@
+package org.baeldung.acl;
+
+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-security-acl/src/test/java/org/baeldung/acl/SpringAclTest.java b/spring-security-acl/src/test/java/org/baeldung/acl/SpringACLIntegrationTest.java
similarity index 98%
rename from spring-security-acl/src/test/java/org/baeldung/acl/SpringAclTest.java
rename to spring-security-acl/src/test/java/org/baeldung/acl/SpringACLIntegrationTest.java
index b864639d74..1460d4f47b 100644
--- a/spring-security-acl/src/test/java/org/baeldung/acl/SpringAclTest.java
+++ b/spring-security-acl/src/test/java/org/baeldung/acl/SpringACLIntegrationTest.java
@@ -31,7 +31,7 @@ import org.springframework.test.context.web.ServletTestExecutionListener;
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
WithSecurityContextTestExecutionListener.class})
-public class SpringAclTest extends AbstractJUnit4SpringContextTests{
+public class SpringACLIntegrationTest extends AbstractJUnit4SpringContextTests{
private static Integer FIRST_MESSAGE_ID = 1;
private static Integer SECOND_MESSAGE_ID = 2;
diff --git a/testing-modules/mockito-2/README.md b/testing-modules/mockito-2/README.md
index 49741c66d1..ee443df81a 100644
--- a/testing-modules/mockito-2/README.md
+++ b/testing-modules/mockito-2/README.md
@@ -1,6 +1,7 @@
### Relevant articles
- [Mockito’s Java 8 Features](http://www.baeldung.com/mockito-2-java-8)
+- [Lazy Verification with Mockito 2](http://www.baeldung.com/mockito-2-lazy-verification)
## Mockito 2 and Java 8 Tips
diff --git a/testing-modules/mockito/README.md b/testing-modules/mockito/README.md
index 0d6f69a64f..4bbc083d8c 100644
--- a/testing-modules/mockito/README.md
+++ b/testing-modules/mockito/README.md
@@ -12,3 +12,5 @@
- [Introduction to PowerMock](http://www.baeldung.com/intro-to-powermock)
- [Mocking Exception Throwing using Mockito](http://www.baeldung.com/mockito-exceptions)
- [Mocking Void Methods with Mockito](http://www.baeldung.com/mockito-void-methods)
+- [Mocking of Private Methods Using PowerMock](http://www.baeldung.com/powermock-private-method)
+- [Mock Final Classes and Methods with Mockito](http://www.baeldung.com/mockito-final)
diff --git a/testing-modules/testing/pom.xml b/testing-modules/testing/pom.xml
index 7aff0a93e0..1fd6357b87 100644
--- a/testing-modules/testing/pom.xml
+++ b/testing-modules/testing/pom.xml
@@ -94,6 +94,11 @@
1.5
test
+
+ org.javalite
+ javalite-common
+ ${javalite.version}
+
@@ -162,5 +167,6 @@
0.32
1.1.0
0.12
+ 1.4.13
diff --git a/testing-modules/testing/src/main/java/com/baeldung/jspec/Animal.java b/testing-modules/testing/src/main/java/com/baeldung/jspec/Animal.java
new file mode 100644
index 0000000000..efb4c62bde
--- /dev/null
+++ b/testing-modules/testing/src/main/java/com/baeldung/jspec/Animal.java
@@ -0,0 +1,41 @@
+package com.baeldung.jspec;
+
+public abstract class Animal {
+
+ protected String name;
+
+ public Animal(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Animal other = (Animal) obj;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ return true;
+ }
+
+
+}
diff --git a/testing-modules/testing/src/main/java/com/baeldung/jspec/Cage.java b/testing-modules/testing/src/main/java/com/baeldung/jspec/Cage.java
new file mode 100644
index 0000000000..73ea343600
--- /dev/null
+++ b/testing-modules/testing/src/main/java/com/baeldung/jspec/Cage.java
@@ -0,0 +1,48 @@
+package com.baeldung.jspec;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+public class Cage {
+
+ private Set animals = new HashSet<>();
+
+ public void put(Animal animal) {
+ animals.add(animal);
+ }
+
+ public void put(Animal... animals) {
+ this.animals.addAll(Arrays.asList(animals));
+ }
+
+ public Animal release(Animal animal) {
+ return animals.remove(animal) ? animal : null;
+ }
+
+ public void open() {
+ animals.clear();
+ }
+
+ public boolean hasAnimals() {
+ return animals.size() > 0;
+ }
+
+ public boolean isEmpty() {
+ return animals.isEmpty();
+ }
+
+ public Set getAnimals() {
+ return this.animals;
+ }
+
+ public int size() {
+ return animals.size();
+ }
+
+ @Override
+ public String toString() {
+ return "Cage [animals=" + animals + "]";
+ }
+
+}
diff --git a/testing-modules/testing/src/main/java/com/baeldung/jspec/Cat.java b/testing-modules/testing/src/main/java/com/baeldung/jspec/Cat.java
new file mode 100644
index 0000000000..5021a1481c
--- /dev/null
+++ b/testing-modules/testing/src/main/java/com/baeldung/jspec/Cat.java
@@ -0,0 +1,14 @@
+package com.baeldung.jspec;
+
+public class Cat extends Animal {
+
+ public Cat(String name) {
+ super(name);
+ }
+
+ @Override
+ public String toString() {
+ return "Cat [name=" + name + "]";
+ }
+
+}
diff --git a/testing-modules/testing/src/main/java/com/baeldung/jspec/Dog.java b/testing-modules/testing/src/main/java/com/baeldung/jspec/Dog.java
new file mode 100644
index 0000000000..43626941e3
--- /dev/null
+++ b/testing-modules/testing/src/main/java/com/baeldung/jspec/Dog.java
@@ -0,0 +1,14 @@
+package com.baeldung.jspec;
+
+public class Dog extends Animal {
+
+ public Dog(String name) {
+ super(name);
+ }
+
+ @Override
+ public String toString() {
+ return "Dog [name=" + name + "]";
+ }
+
+}
diff --git a/testing-modules/testing/src/test/java/com/baeldung/jspec/CageUnitTest.java b/testing-modules/testing/src/test/java/com/baeldung/jspec/CageUnitTest.java
new file mode 100644
index 0000000000..33ef986588
--- /dev/null
+++ b/testing-modules/testing/src/test/java/com/baeldung/jspec/CageUnitTest.java
@@ -0,0 +1,126 @@
+package com.baeldung.jspec;
+
+import static org.javalite.test.jspec.JSpec.$;
+import static org.javalite.test.jspec.JSpec.expect;
+import static org.javalite.test.jspec.JSpec.the;
+
+import java.util.Set;
+
+import org.javalite.test.jspec.DifferenceExpectation;
+import org.junit.Test;
+
+public class CageUnitTest {
+
+ Cat tomCat = new Cat("Tom");
+ Cat felixCat = new Cat("Felix");
+ Dog boltDog = new Dog("Bolt");
+ Cage cage = new Cage();
+
+
+ @Test
+ public void puttingAnimals_shouldIncreaseCageSize() {
+ // When
+ cage.put(tomCat, boltDog);
+
+ // Then
+ the(cage.size()).shouldEqual(2);
+ }
+
+ @Test
+ public void releasingAnimals_shouldDecreaseCageSize() {
+ // When
+ cage.put(tomCat, boltDog);
+ cage.release(tomCat);
+
+ // Then
+ the(cage.size()).shouldEqual(1);
+ }
+
+ @Test
+ public void puttingAnimals_shouldLeaveThemInsideTheCage() {
+ // When
+ cage.put(tomCat, boltDog);
+
+ // Then
+ the(cage).shouldHave("animals");
+ }
+
+ @Test
+ public void openingTheCage_shouldReleaseAllAnimals() {
+ // When
+ cage.put(tomCat, boltDog);
+
+ // Then
+ the(cage).shouldNotBe("empty");
+
+ // When
+ cage.open();
+
+ // Then
+ the(cage).shouldBe("empty");
+ the(cage.isEmpty()).shouldBeTrue();
+ }
+
+ @Test
+ public void comparingTwoDogs() {
+ // When
+ Dog firstDog = new Dog("Rex");
+ Dog secondDog = new Dog("Rex");
+
+ // Then
+ $(firstDog).shouldEqual(secondDog);
+ $(firstDog).shouldNotBeTheSameAs(secondDog);
+ }
+
+ @Test
+ public void puttingCatsOnly_shouldLetCageAnimalsToContainCats() {
+ // When
+ cage.put(tomCat, felixCat);
+
+ // Then
+ Set animals = cage.getAnimals();
+ the(animals).shouldContain(tomCat);
+ the(animals).shouldContain(felixCat);
+ the(animals).shouldNotContain(boltDog);
+ }
+
+ @Test
+ public void puttingCatsOnly_shouldLetCageToContainCats() {
+ // When
+ cage.put(tomCat, felixCat);
+
+ // Then
+ // Check with toString of the tested objects
+ the(cage).shouldContain(tomCat);
+ the(cage).shouldContain(felixCat);
+ the(cage).shouldNotContain(boltDog);
+ }
+
+ @Test
+ public void puttingMoreAnimals_shouldChangeSize() {
+ // When
+ cage.put(tomCat, boltDog);
+
+ // Then
+ expect( new DifferenceExpectation(cage.size()) {
+
+ @Override
+ public Integer exec() {
+ cage.release(tomCat);
+ return cage.size();
+ }
+ } );
+ }
+
+
+ @Test
+ public void releasingTheDog_shouldReleaseAnAnimalOfDogType() {
+ // When
+ cage.put(boltDog);
+ Animal releasedAnimal = cage.release(boltDog);
+
+ // Then
+ the(releasedAnimal).shouldNotBeNull();
+ the(releasedAnimal).shouldBeA(Dog.class);
+ }
+}
diff --git a/testing-modules/testing/src/test/java/com/baeldung/jspec/JSpecUnitTest.java b/testing-modules/testing/src/test/java/com/baeldung/jspec/JSpecUnitTest.java
new file mode 100644
index 0000000000..0e35e26728
--- /dev/null
+++ b/testing-modules/testing/src/test/java/com/baeldung/jspec/JSpecUnitTest.java
@@ -0,0 +1,57 @@
+package com.baeldung.jspec;
+
+import static org.javalite.test.jspec.JSpec.$;
+import static org.javalite.test.jspec.JSpec.a;
+import static org.javalite.test.jspec.JSpec.expect;
+import static org.javalite.test.jspec.JSpec.it;
+import static org.javalite.test.jspec.JSpec.the;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.javalite.test.jspec.ExceptionExpectation;
+import org.junit.Test;
+
+public class JSpecUnitTest {
+
+ @Test
+ public void onePlusTwo_shouldEqualThree() {
+ $(1 + 2).shouldEqual(3);
+ a(1 + 2).shouldEqual(3);
+ the(1 + 2).shouldEqual(3);
+ it(1 + 2).shouldEqual(3);
+ }
+
+ @Test
+ public void messageShouldContainJSpec() {
+ String message = "Welcome to JSpec demo";
+ // The message should not be empty
+ the(message).shouldNotBe("empty");
+ // The message should contain JSpec
+ the(message).shouldContain("JSpec");
+ }
+
+ public void colorsListShouldContainRed() {
+ List colorsList = Arrays.asList("red", "green", "blue");
+ $(colorsList).shouldContain("red");
+ }
+
+ public void guessedNumberShouldEqualHiddenNumber() {
+ Integer guessedNumber = 11;
+ Integer hiddenNumber = 11;
+
+ $(guessedNumber).shouldEqual(hiddenNumber);
+ $(guessedNumber).shouldNotBeTheSameAs(hiddenNumber);
+ }
+
+ @Test
+ public void dividingByThero_shouldThrowArithmeticException() {
+ expect(new ExceptionExpectation(ArithmeticException.class) {
+ @Override
+ public void exec() throws ArithmeticException {
+ System.out.println(1 / 0);
+ }
+ } );
+ }
+
+}