Merge remote-tracking branch 'upstream/master' into tutorials/binaryTreeJava
This commit is contained in:
commit
1fa5e1a8e3
|
@ -0,0 +1,2 @@
|
||||||
|
## Relevant articles:
|
||||||
|
- [CAS SSO With Spring Security](http://www.baeldung.com/spring-security-cas-sso)
|
|
@ -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)
|
- [“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)
|
- [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)
|
- [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)
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.baeldung.stream;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
class PrimitiveStreams {
|
||||||
|
|
||||||
|
int min(int[] integers) {
|
||||||
|
return Arrays.stream(integers).min().getAsInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
int max(int... integers) {
|
||||||
|
return IntStream.of(integers).max().getAsInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
int sum(int... integers) {
|
||||||
|
return IntStream.of(integers).sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
double avg(int... integers) {
|
||||||
|
return IntStream.of(integers).average().getAsDouble();
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,23 +38,14 @@ public class CounterUtil {
|
||||||
|
|
||||||
public static void counterWithMutableInteger(Map<String, MutableInteger> counterMap) {
|
public static void counterWithMutableInteger(Map<String, MutableInteger> counterMap) {
|
||||||
for (String country : COUNTRY_NAMES) {
|
for (String country : COUNTRY_NAMES) {
|
||||||
MutableInteger oldValue = counterMap.get(country);
|
counterMap.compute(country, (k, v) -> v == null ? new MutableInteger(0) : v)
|
||||||
if (oldValue != null) {
|
.increment();
|
||||||
oldValue.increment();
|
|
||||||
} else {
|
|
||||||
counterMap.put(country, new MutableInteger(1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void counterWithPrimitiveArray(Map<String, int[]> counterMap) {
|
public static void counterWithPrimitiveArray(Map<String, int[]> counterMap) {
|
||||||
for (String country : COUNTRY_NAMES) {
|
for (String country : COUNTRY_NAMES) {
|
||||||
int[] oldCounter = counterMap.get(country);
|
counterMap.compute(country, (k, v) -> v == null ? new int[] { 0 } : v)[0]++;
|
||||||
if (oldCounter != null) {
|
|
||||||
oldCounter[0] += 1;
|
|
||||||
} else {
|
|
||||||
counterMap.put(country, new int[] { 1 });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
package com.baeldung.stream;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class PrimitiveStreamsUnitTest {
|
||||||
|
|
||||||
|
private PrimitiveStreams streams = new PrimitiveStreams();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAnArrayOfIntegersWhenMinIsCalledThenCorrectMinIsReturned() {
|
||||||
|
int[] integers = new int[] {20, 98, 12, 7, 35};
|
||||||
|
int min = streams.min(integers); // returns 7
|
||||||
|
|
||||||
|
assertEquals(7, min);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAnArrayOfIntegersWhenMaxIsCalledThenCorrectMaxIsReturned() {
|
||||||
|
int max = streams.max(20, 98, 12, 7, 35);
|
||||||
|
|
||||||
|
assertEquals(98, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAnArrayOfIntegersWhenSumIsCalledThenCorrectSumIsReturned() {
|
||||||
|
int sum = streams.sum(20, 98, 12, 7, 35);
|
||||||
|
|
||||||
|
assertEquals(172, sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAnArrayOfIntegersWhenAvgIsCalledThenCorrectAvgIsReturned() {
|
||||||
|
double avg = streams.avg(20, 98, 12, 7, 35);
|
||||||
|
|
||||||
|
assertTrue(34.4 == avg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenARangeOfIntegersWhenIntStreamSumIsCalledThenCorrectSumIsReturned() {
|
||||||
|
int sum = IntStream.range(1, 10).sum();
|
||||||
|
|
||||||
|
assertEquals(45, sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenARangeClosedOfIntegersWhenIntStreamSumIsCalledThenCorrectSumIsReturned() {
|
||||||
|
int sum = IntStream.rangeClosed(1, 10).sum();
|
||||||
|
|
||||||
|
assertEquals(55, sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenARangeWhenForEachIsCalledThenTheIndicesWillBePrinted() {
|
||||||
|
IntStream.rangeClosed(1, 5).parallel().forEach(System.out::println);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAnArrayWhenSumIsCalledThenTheCorrectSumIsReturned() {
|
||||||
|
|
||||||
|
int sum = Arrays.asList(33,45).stream().mapToInt(a -> a).sum();
|
||||||
|
|
||||||
|
assertEquals(78, sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAnIntStreamThenGetTheEvenIntegers() {
|
||||||
|
List<Integer> evenInts = IntStream.rangeClosed(1, 10)
|
||||||
|
.filter(i -> i % 2 == 0)
|
||||||
|
.boxed()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<Integer> expected = IntStream.of(2, 4, 6, 8, 10).boxed().collect(Collectors.toList());
|
||||||
|
|
||||||
|
assertEquals(expected, evenInts);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Person {
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
Person(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,3 +18,4 @@
|
||||||
- [How to Get All Dates Between Two Dates?](http://www.baeldung.com/java-between-dates)
|
- [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)
|
- [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)
|
- [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)
|
||||||
|
|
|
@ -31,3 +31,5 @@
|
||||||
- [Overview of the java.util.concurrent](http://www.baeldung.com/java-util-concurrent)
|
- [Overview of the java.util.concurrent](http://www.baeldung.com/java-util-concurrent)
|
||||||
- [Semaphores in Java](http://www.baeldung.com/java-semaphore)
|
- [Semaphores in Java](http://www.baeldung.com/java-semaphore)
|
||||||
- [Daemon Threads in Java](http://www.baeldung.com/java-daemon-thread)
|
- [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)
|
||||||
|
|
|
@ -10,9 +10,9 @@ import java.util.concurrent.*;
|
||||||
|
|
||||||
import static junit.framework.TestCase.assertTrue;
|
import static junit.framework.TestCase.assertTrue;
|
||||||
|
|
||||||
public class WaitingForThreadsToFinishTest {
|
public class WaitingForThreadsToFinishManualTest {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(WaitingForThreadsToFinishTest.class);
|
private static final Logger LOG = LoggerFactory.getLogger(WaitingForThreadsToFinishManualTest.class);
|
||||||
private final static ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool(10);
|
private final static ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool(10);
|
||||||
|
|
||||||
public void awaitTerminationAfterShutdown(ExecutorService threadPool) {
|
public void awaitTerminationAfterShutdown(ExecutorService threadPool) {
|
||||||
|
@ -142,66 +142,4 @@ public class WaitingForThreadsToFinishTest {
|
||||||
awaitTerminationAfterShutdown(WORKER_THREAD_POOL);
|
awaitTerminationAfterShutdown(WORKER_THREAD_POOL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void givenMultipleThreads_whenUsingCompletableFutures_thenMainThreadShouldWaitForAllToFinish() {
|
|
||||||
|
|
||||||
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(1000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Hello";
|
|
||||||
});
|
|
||||||
|
|
||||||
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(5000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Beautiful";
|
|
||||||
});
|
|
||||||
|
|
||||||
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(3000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return "World";
|
|
||||||
});
|
|
||||||
|
|
||||||
long startProcessingTime = System.currentTimeMillis();
|
|
||||||
CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(future1, future2, future3);
|
|
||||||
combinedFuture.join();
|
|
||||||
|
|
||||||
long totalProcessingTime = System.currentTimeMillis() - startProcessingTime;
|
|
||||||
assertTrue(totalProcessingTime >= 5000 && totalProcessingTime < 6000);
|
|
||||||
|
|
||||||
LOG.debug("Responses from all threads are available after " + totalProcessingTime + " milliseconds");
|
|
||||||
|
|
||||||
try {
|
|
||||||
String thread1Response = future1.get();
|
|
||||||
assertTrue(thread1Response.equals("Hello"));
|
|
||||||
|
|
||||||
String thread2Response = future2.get();
|
|
||||||
assertTrue(thread2Response.equals("Beautiful"));
|
|
||||||
|
|
||||||
String thread3Response = future3.get();
|
|
||||||
assertTrue(thread3Response.equals("World"));
|
|
||||||
|
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
awaitTerminationAfterShutdown(WORKER_THREAD_POOL);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -121,4 +121,8 @@
|
||||||
- [Copy a File with Java](http://www.baeldung.com/java-copy-file)
|
- [Copy a File with Java](http://www.baeldung.com/java-copy-file)
|
||||||
- [Introduction to Creational Design Patterns](http://www.baeldung.com/creational-design-patterns)
|
- [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 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)
|
||||||
|
|
|
@ -5,12 +5,12 @@ import org.openjdk.jmh.annotations.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@BenchmarkMode(Mode.AverageTime)
|
||||||
|
@Warmup(iterations = 5)
|
||||||
|
@OutputTimeUnit(TimeUnit.MICROSECONDS)
|
||||||
public class SearchArrayTest {
|
public class SearchArrayTest {
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
@BenchmarkMode(Mode.AverageTime)
|
|
||||||
@Warmup(iterations = 5)
|
|
||||||
@OutputTimeUnit(TimeUnit.MICROSECONDS)
|
|
||||||
public void searchArrayLoop() {
|
public void searchArrayLoop() {
|
||||||
|
|
||||||
int count = 1000;
|
int count = 1000;
|
||||||
|
@ -21,9 +21,6 @@ public class SearchArrayTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
@BenchmarkMode(Mode.AverageTime)
|
|
||||||
@Warmup(iterations = 5)
|
|
||||||
@OutputTimeUnit(TimeUnit.MICROSECONDS)
|
|
||||||
public void searchArrayAllocNewList() {
|
public void searchArrayAllocNewList() {
|
||||||
|
|
||||||
int count = 1000;
|
int count = 1000;
|
||||||
|
@ -35,9 +32,6 @@ public class SearchArrayTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
@BenchmarkMode(Mode.AverageTime)
|
|
||||||
@Warmup(iterations = 5)
|
|
||||||
@OutputTimeUnit(TimeUnit.MICROSECONDS)
|
|
||||||
public void searchArrayAllocNewSet() {
|
public void searchArrayAllocNewSet() {
|
||||||
|
|
||||||
int count = 1000;
|
int count = 1000;
|
||||||
|
@ -49,9 +43,6 @@ public class SearchArrayTest {
|
||||||
|
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
@BenchmarkMode(Mode.AverageTime)
|
|
||||||
@Warmup(iterations = 5)
|
|
||||||
@OutputTimeUnit(TimeUnit.MICROSECONDS)
|
|
||||||
public void searchArrayReuseList() {
|
public void searchArrayReuseList() {
|
||||||
|
|
||||||
int count = 1000;
|
int count = 1000;
|
||||||
|
@ -66,9 +57,6 @@ public class SearchArrayTest {
|
||||||
|
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
@BenchmarkMode(Mode.AverageTime)
|
|
||||||
@Warmup(iterations = 5)
|
|
||||||
@OutputTimeUnit(TimeUnit.MICROSECONDS)
|
|
||||||
public void searchArrayReuseSet() {
|
public void searchArrayReuseSet() {
|
||||||
|
|
||||||
int count = 1000;
|
int count = 1000;
|
||||||
|
@ -81,9 +69,6 @@ public class SearchArrayTest {
|
||||||
|
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
@BenchmarkMode(Mode.AverageTime)
|
|
||||||
@Warmup(iterations = 5)
|
|
||||||
@OutputTimeUnit(TimeUnit.MICROSECONDS)
|
|
||||||
public void searchArrayBinarySearch() {
|
public void searchArrayBinarySearch() {
|
||||||
|
|
||||||
int count = 1000;
|
int count = 1000;
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.baeldung.interfaces;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class CommaSeparatedCustomers implements Customer.List {
|
||||||
|
|
||||||
|
private List<Customer> customers = new ArrayList<Customer>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void Add(Customer customer) {
|
||||||
|
customers.add(customer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCustomerNames() {
|
||||||
|
return customers.stream().map(customer -> customer.getName()).collect(Collectors.joining(","));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.baeldung.interfaces;
|
||||||
|
|
||||||
|
public class Customer {
|
||||||
|
public interface List {
|
||||||
|
void Add(Customer customer);
|
||||||
|
|
||||||
|
String getCustomerNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Customer(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,7 +54,7 @@ public class GenericFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFileInfo() {
|
public String getFileInfo() {
|
||||||
return String.format("File Name: %s\n" + " Extension: %s\n" + " Date Created: %s\n" + " Version: %s\n", this.getName(), this.getExtension(), this.getDateCreated(), this.getVersion());
|
return "Generic File Impl";
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object read() {
|
public Object read() {
|
||||||
|
|
|
@ -30,7 +30,7 @@ public class ImageFile extends GenericFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFileInfo() {
|
public String getFileInfo() {
|
||||||
return String.format(" %s Height: %d\n Width: %d", super.getFileInfo(), this.getHeight(), this.getWidth());
|
return "Image File Impl";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String read() {
|
public String read() {
|
||||||
|
|
|
@ -21,7 +21,7 @@ public class TextFile extends GenericFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFileInfo() {
|
public String getFileInfo() {
|
||||||
return String.format(" %s Word Count: %d", super.getFileInfo(), wordCount);
|
return "Text File Impl";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String read() {
|
public String read() {
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.baeldung.interfaces;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public class InnerInterfaceTests {
|
||||||
|
@Test
|
||||||
|
public void whenCustomerListJoined_thenReturnsJoinedNames() {
|
||||||
|
Customer.List customerList = new CommaSeparatedCustomers();
|
||||||
|
customerList.Add(new Customer("customer1"));
|
||||||
|
customerList.Add(new Customer("customer2"));
|
||||||
|
assertEquals("customer1,customer2", customerList.getCustomerNames());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
- [Introduction to Drools](http://www.baeldung.com/drools)
|
- [Introduction to Drools](http://www.baeldung.com/drools)
|
||||||
- [Drools Using Rules from Excel Files](http://www.baeldung.com/drools-excel)
|
- [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)
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<artifactId>flyway</artifactId>
|
|
||||||
<version>1.0</version>
|
|
||||||
<name>flyway</name>
|
|
||||||
<packaging>pom</packaging>
|
|
||||||
<description>A sample project to demonstrate Flyway migrations</description>
|
|
||||||
|
|
||||||
<parent>
|
|
||||||
<groupId>com.baeldung</groupId>
|
|
||||||
<artifactId>parent-modules</artifactId>
|
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<modules>
|
|
||||||
<module>spring-flyway</module>
|
|
||||||
</modules>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>mysql</groupId>
|
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
|
||||||
<version>${mysql.version}</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<dependencyManagement>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-dependencies</artifactId>
|
|
||||||
<version>${spring.boot.version}</version>
|
|
||||||
<type>pom</type>
|
|
||||||
<scope>import</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</dependencyManagement>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.flywaydb</groupId>
|
|
||||||
<artifactId>flyway-maven-plugin</artifactId>
|
|
||||||
<version>${flyway-maven-plugin.version}</version>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
<properties>
|
|
||||||
<mysql.version>6.0.5</mysql.version>
|
|
||||||
<flyway-maven-plugin.version>4.0.3</flyway-maven-plugin.version>
|
|
||||||
<spring.boot.version>1.5.8.RELEASE</spring.boot.version>
|
|
||||||
</properties>
|
|
||||||
</project>
|
|
|
@ -1,57 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>spring-flyway</artifactId>
|
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
|
|
||||||
<name>spring-flyway</name>
|
|
||||||
<description>Spring Boot Test Flyway Migrations</description>
|
|
||||||
|
|
||||||
<parent>
|
|
||||||
<artifactId>flyway</artifactId>
|
|
||||||
<groupId>com.baeldung</groupId>
|
|
||||||
<version>1.0</version>
|
|
||||||
<relativePath>../../flyway</relativePath>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
|
||||||
<java.version>1.8</java.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.flywaydb</groupId>
|
|
||||||
<artifactId>flyway-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.h2database</groupId>
|
|
||||||
<artifactId>h2</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
|
|
@ -1,28 +0,0 @@
|
||||||
package com.baeldung.springflyway.entities;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.GeneratedValue;
|
|
||||||
import javax.persistence.Id;
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
@Builder
|
|
||||||
public class Customer {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
private String firstName;
|
|
||||||
private String lastName;
|
|
||||||
|
|
||||||
private String email;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
package com.baeldung.springflyway.migration;
|
|
||||||
|
|
||||||
import org.flywaydb.core.api.migration.spring.SpringJdbcMigration;
|
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
|
||||||
|
|
||||||
public class V2__uk_lastname_customer implements SpringJdbcMigration {
|
|
||||||
|
|
||||||
final String CUSTOMER_LASTNAME_UK = "ALTER TABLE customer ADD CONSTRAINT uk_customer_lastname UNIQUE(last_name);";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void migrate(final JdbcTemplate jdbcTemplate) throws Exception {
|
|
||||||
jdbcTemplate.execute(CUSTOMER_LASTNAME_UK);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
package com.baeldung.springflyway.repositories;
|
|
||||||
|
|
||||||
import com.baeldung.springflyway.entities.Customer;
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public interface CustomerRepository extends JpaRepository<Customer, Long> {
|
|
||||||
|
|
||||||
Optional<Customer> findByEmail(String email);
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
package com.baeldung.springflyway;
|
|
||||||
|
|
||||||
import com.baeldung.springflyway.entities.Customer;
|
|
||||||
import com.baeldung.springflyway.repositories.CustomerRepository;
|
|
||||||
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.junit.Assert.assertNotNull;
|
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@SpringBootTest
|
|
||||||
public class CustomerRepositoryInitialMigrationTest {
|
|
||||||
|
|
||||||
@Autowired CustomerRepository customerRepository;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void givenSchemaCreationMigration_whenTryingToCreateACustomer_thenSuccess() {
|
|
||||||
Customer customer = customerRepository.save(Customer
|
|
||||||
.builder()
|
|
||||||
.email("customer@email.com")
|
|
||||||
.build());
|
|
||||||
assertNotNull(customer.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
package com.baeldung.springflyway;
|
|
||||||
|
|
||||||
import com.baeldung.springflyway.entities.Customer;
|
|
||||||
import com.baeldung.springflyway.repositories.CustomerRepository;
|
|
||||||
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 java.util.Optional;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@SpringBootTest
|
|
||||||
public class CustomerRepositoryInsertDataMigrationTest {
|
|
||||||
|
|
||||||
@Autowired CustomerRepository customerRepository;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void givenASetInsertData_whenRunningMigrationsWithSuccess_thenASpecificCustomerIsFound() {
|
|
||||||
Optional<Customer> customerOptional = customerRepository.findByEmail("email@email.com");
|
|
||||||
assertTrue(customerOptional.isPresent());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void givenASetInsertData_whenRunningMigrationsWithSuccess_thenASetOfCustomersIsFound() {
|
|
||||||
List<Customer> customers = customerRepository.findAll();
|
|
||||||
assertNotNull(customers);
|
|
||||||
assertEquals(customers.size(), 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
package com.baeldung.springflyway;
|
|
||||||
|
|
||||||
import com.baeldung.springflyway.entities.Customer;
|
|
||||||
import com.baeldung.springflyway.repositories.CustomerRepository;
|
|
||||||
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.dao.DataIntegrityViolationException;
|
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@SpringBootTest
|
|
||||||
public class CustomerRepositoryNotNullConstraintMigrationTest {
|
|
||||||
|
|
||||||
@Autowired CustomerRepository customerRepository;
|
|
||||||
|
|
||||||
@Test(expected = DataIntegrityViolationException.class)
|
|
||||||
public void givenTheNotNullConstraintMigrations_whenInsertingACustomerWithNullEmail_thenThrowException() {
|
|
||||||
customerRepository.save(Customer
|
|
||||||
.builder()
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package com.baeldung.springflyway;
|
|
||||||
|
|
||||||
import com.baeldung.springflyway.entities.Customer;
|
|
||||||
import com.baeldung.springflyway.repositories.CustomerRepository;
|
|
||||||
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.dao.DataIntegrityViolationException;
|
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@SpringBootTest(properties = {
|
|
||||||
"flyway.locations[0]=db/migration", "flyway.locations[1]=com/baeldung/springflyway/migration"
|
|
||||||
})
|
|
||||||
public class CustomerRepositoryUniqueConstraintJavaMigrationTest {
|
|
||||||
|
|
||||||
@Autowired CustomerRepository customerRepository;
|
|
||||||
|
|
||||||
@Test(expected = DataIntegrityViolationException.class)
|
|
||||||
public void givenTheUniqueConstraintMigrations_whenInsertingAnExistingLastNameCustomer_thenThrowException() {
|
|
||||||
customerRepository.save(Customer
|
|
||||||
.builder()
|
|
||||||
.lastName("LastName")
|
|
||||||
.build());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package com.baeldung.springflyway;
|
|
||||||
|
|
||||||
import com.baeldung.springflyway.entities.Customer;
|
|
||||||
import com.baeldung.springflyway.repositories.CustomerRepository;
|
|
||||||
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.dao.DataIntegrityViolationException;
|
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@SpringBootTest
|
|
||||||
public class CustomerRepositoryUniqueConstraintMigrationTest {
|
|
||||||
|
|
||||||
@Autowired CustomerRepository customerRepository;
|
|
||||||
|
|
||||||
@Test(expected = DataIntegrityViolationException.class)
|
|
||||||
public void givenTheUniqueConstraintMigrations_whenInsertingAnExistingEmailCustomer_thenThrowException() {
|
|
||||||
customerRepository.save(Customer
|
|
||||||
.builder()
|
|
||||||
.email("email@email.com")
|
|
||||||
.build());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
spring.jpa.hibernate.ddl-auto=validate
|
|
|
@ -1,6 +0,0 @@
|
||||||
create table if not exists customer (
|
|
||||||
id bigint AUTO_INCREMENT not null primary key,
|
|
||||||
first_name varchar(255) ,
|
|
||||||
last_name varchar(255) ,
|
|
||||||
email varchar(255)
|
|
||||||
);
|
|
|
@ -1,6 +0,0 @@
|
||||||
insert into customer (first_name, last_name, email) values ('FirstName', 'LastName', 'email@email.com');
|
|
||||||
insert into customer (first_name, last_name, email) values ('FirstName1', 'LastName1', 'email1@email.com');
|
|
||||||
insert into customer (first_name, last_name, email) values ('FirstName2', 'LastName2', 'email2@email.com');
|
|
||||||
insert into customer (first_name, last_name, email) values ('FirstName3', 'LastName3', 'email3@email.com');
|
|
||||||
insert into customer (first_name, last_name, email) values ('FirstName4', 'LastName4', 'email4@email.com');
|
|
||||||
insert into customer (first_name, last_name, email) values ('FirstName5', 'LastName5', 'email5@email.com');
|
|
|
@ -1 +0,0 @@
|
||||||
ALTER TABLE customer ALTER email SET NOT NULL;
|
|
|
@ -1 +0,0 @@
|
||||||
ALTER TABLE customer ADD CONSTRAINT uk_customer_email UNIQUE(email);
|
|
|
@ -1 +1,2 @@
|
||||||
## Relevant articles:
|
## Relevant articles:
|
||||||
|
- [Introduction to Gradle](http://www.baeldung.com/gradle)
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
repositories{
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
apply plugin: 'java'
|
||||||
|
apply plugin: 'maven'
|
||||||
|
apply plugin: com.baeldung.GreetingPlugin
|
||||||
|
dependencies {
|
||||||
|
compile gradleApi()
|
||||||
|
}
|
||||||
|
|
||||||
|
greeting {
|
||||||
|
greeter = "Stranger"
|
||||||
|
message = "Message from the build script!"
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.baeldung;
|
||||||
|
|
||||||
|
import org.gradle.api.Plugin;
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
|
||||||
|
public class GreetingPlugin implements Plugin<Project> {
|
||||||
|
@Override
|
||||||
|
public void apply(Project project) {
|
||||||
|
|
||||||
|
GreetingPluginExtension extension = project.getExtensions().create("greeting", GreetingPluginExtension.class);
|
||||||
|
|
||||||
|
project.task("hello").doLast(task -> {
|
||||||
|
System.out.println("Hello, " + extension.getGreeter());
|
||||||
|
System.out.println("I have a message for You: " + extension.getMessage()); }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.baeldung;
|
||||||
|
|
||||||
|
public class GreetingPluginExtension {
|
||||||
|
private String greeter = "Baeldung";
|
||||||
|
private String message = "Message from Plugin!";
|
||||||
|
|
||||||
|
public String getGreeter() {
|
||||||
|
return greeter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGreeter(String greeter) {
|
||||||
|
this.greeter = greeter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,3 +2,5 @@
|
||||||
|
|
||||||
- [Dynamic Mapping with Hibernate](http://www.baeldung.com/hibernate-dynamic-mapping)
|
- [Dynamic Mapping with Hibernate](http://www.baeldung.com/hibernate-dynamic-mapping)
|
||||||
- [An Overview of Identifiers in Hibernate](http://www.baeldung.com/hibernate-identifiers)
|
- [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)
|
||||||
|
|
|
@ -1,20 +1,7 @@
|
||||||
BASIC CRUD API with Spring Boot
|
BASIC CRUD API with Spring Boot
|
||||||
================================
|
================================
|
||||||
|
|
||||||
This is the code of a simple API for some CRUD operations realised for a seminar at [FGI](www.fgi-ud.org) using Spring Boot.
|
This is the code of a simple API for some CRUD operations build using Spring Boot.
|
||||||
|
|
||||||
### Demo
|
|
||||||
* API: The online version **is**/**will be** hosted here: https://fgi-tcheck.herokuapp.com
|
|
||||||
* Mobile version is also opensource and located here: https://github.com/valdesekamdem/tcheck-mobile
|
|
||||||
|
|
||||||
### Features
|
|
||||||
#### Currently Implemented
|
|
||||||
* CRUD
|
|
||||||
* Student
|
|
||||||
|
|
||||||
#### To DO
|
|
||||||
* Validations of input with: [Spring Data Rest Validators](http://docs.spring.io/spring-data/rest/docs/2.1.0.RELEASE/reference/html/validation-chapter.html)
|
|
||||||
|
|
||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
|
|
||||||
|
@ -49,7 +36,6 @@ Or create a new one via a POST:
|
||||||
$ curl -X POST -H "Content-Type:application/json" -d '{ "firstName" : "Dassi", "lastName" : "Orleando", "phoneNumber": "+237 545454545", "email": "mymail@yahoo.fr" }' localhost:8080/students
|
$ curl -X POST -H "Content-Type:application/json" -d '{ "firstName" : "Dassi", "lastName" : "Orleando", "phoneNumber": "+237 545454545", "email": "mymail@yahoo.fr" }' localhost:8080/students
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Now with default configurations it will be available at: [http://localhost:8080](http://localhost:8080)
|
Now with default configurations it will be available at: [http://localhost:8080](http://localhost:8080)
|
||||||
|
|
||||||
Enjoy it :)
|
Enjoy it :)
|
|
@ -0,0 +1,68 @@
|
||||||
|
2017-12-13 04:50:16,291 INFO o.a.j.u.JMeterUtils: Setting Locale to en_US
|
||||||
|
2017-12-13 04:50:16,319 INFO o.a.j.JMeter: Loading user properties from: /Users/dassiorleando/projects/biz/baeldung/jmeter/apache-jmeter-3.3/bin/user.properties
|
||||||
|
2017-12-13 04:50:16,392 INFO o.a.j.JMeter: Loading system properties from: /Users/dassiorleando/projects/biz/baeldung/jmeter/apache-jmeter-3.3/bin/system.properties
|
||||||
|
2017-12-13 04:50:16,406 INFO o.a.j.JMeter: Setting JMeter property: jmeter.save.saveservice.output_format=xml
|
||||||
|
2017-12-13 04:50:16,451 INFO o.a.j.JMeter: Copyright (c) 1998-2017 The Apache Software Foundation
|
||||||
|
2017-12-13 04:50:16,451 INFO o.a.j.JMeter: Version 3.3 r1808647
|
||||||
|
2017-12-13 04:50:16,451 INFO o.a.j.JMeter: java.version=1.8.0_152
|
||||||
|
2017-12-13 04:50:16,451 INFO o.a.j.JMeter: java.vm.name=Java HotSpot(TM) 64-Bit Server VM
|
||||||
|
2017-12-13 04:50:16,451 INFO o.a.j.JMeter: os.name=Mac OS X
|
||||||
|
2017-12-13 04:50:16,451 INFO o.a.j.JMeter: os.arch=x86_64
|
||||||
|
2017-12-13 04:50:16,452 INFO o.a.j.JMeter: os.version=10.12.6
|
||||||
|
2017-12-13 04:50:16,452 INFO o.a.j.JMeter: file.encoding=UTF-8
|
||||||
|
2017-12-13 04:50:16,452 INFO o.a.j.JMeter: Max memory =536870912
|
||||||
|
2017-12-13 04:50:16,452 INFO o.a.j.JMeter: Available Processors =4
|
||||||
|
2017-12-13 04:50:16,461 INFO o.a.j.JMeter: Default Locale=English (United States)
|
||||||
|
2017-12-13 04:50:16,462 INFO o.a.j.JMeter: JMeter Locale=English (United States)
|
||||||
|
2017-12-13 04:50:16,462 INFO o.a.j.JMeter: JMeterHome=/Users/dassiorleando/projects/biz/baeldung/jmeter/apache-jmeter-3.3
|
||||||
|
2017-12-13 04:50:16,462 INFO o.a.j.JMeter: user.dir =/Users/dassiorleando/projects/biz/baeldung/tutorials/jmeter
|
||||||
|
2017-12-13 04:50:16,462 INFO o.a.j.JMeter: PWD =/Users/dassiorleando/projects/biz/baeldung/tutorials/jmeter
|
||||||
|
2017-12-13 04:50:16,466 INFO o.a.j.JMeter: IP: 192.168.10.100 Name: MBP FullName: 192.168.10.100
|
||||||
|
2017-12-13 04:50:16,472 INFO o.a.j.s.FileServer: Default base='/Users/dassiorleando/projects/biz/baeldung/tutorials/jmeter'
|
||||||
|
2017-12-13 04:50:16,473 INFO o.a.j.s.FileServer: Set new base='/Users/dassiorleando/projects/biz/baeldung/tutorials/jmeter/src/main/resources'
|
||||||
|
2017-12-13 04:50:17,022 INFO o.a.j.s.SaveService: Testplan (JMX) version: 2.2. Testlog (JTL) version: 2.2
|
||||||
|
2017-12-13 04:50:17,134 INFO o.a.j.s.SaveService: Using SaveService properties file encoding UTF-8
|
||||||
|
2017-12-13 04:50:17,142 INFO o.a.j.s.SaveService: Using SaveService properties version 3.2
|
||||||
|
2017-12-13 04:50:17,168 INFO o.a.j.s.SaveService: Loading file: src/main/resources/JMeter.jmx
|
||||||
|
2017-12-13 04:50:17,340 INFO o.a.j.p.h.s.HTTPSamplerBase: Parser for text/html is org.apache.jmeter.protocol.http.parser.LagartoBasedHtmlParser
|
||||||
|
2017-12-13 04:50:17,351 INFO o.a.j.p.h.s.HTTPSamplerBase: Parser for application/xhtml+xml is org.apache.jmeter.protocol.http.parser.LagartoBasedHtmlParser
|
||||||
|
2017-12-13 04:50:17,352 INFO o.a.j.p.h.s.HTTPSamplerBase: Parser for application/xml is org.apache.jmeter.protocol.http.parser.LagartoBasedHtmlParser
|
||||||
|
2017-12-13 04:50:17,352 INFO o.a.j.p.h.s.HTTPSamplerBase: Parser for text/xml is org.apache.jmeter.protocol.http.parser.LagartoBasedHtmlParser
|
||||||
|
2017-12-13 04:50:17,353 INFO o.a.j.p.h.s.HTTPSamplerBase: Parser for text/vnd.wap.wml is org.apache.jmeter.protocol.http.parser.RegexpHTMLParser
|
||||||
|
2017-12-13 04:50:17,353 INFO o.a.j.p.h.s.HTTPSamplerBase: Parser for text/css is org.apache.jmeter.protocol.http.parser.CssParser
|
||||||
|
2017-12-13 04:50:17,552 INFO o.a.j.JMeter: Creating summariser <summary>
|
||||||
|
2017-12-13 04:50:17,580 INFO o.a.j.e.StandardJMeterEngine: Running the test!
|
||||||
|
2017-12-13 04:50:17,581 INFO o.a.j.s.SampleEvent: List of sample_variables: []
|
||||||
|
2017-12-13 04:50:17,582 INFO o.a.j.s.SampleEvent: List of sample_variables: []
|
||||||
|
2017-12-13 04:50:17,590 INFO o.a.j.e.u.CompoundVariable: Note: Function class names must contain the string: '.functions.'
|
||||||
|
2017-12-13 04:50:17,590 INFO o.a.j.e.u.CompoundVariable: Note: Function class names must not contain the string: '.gui.'
|
||||||
|
2017-12-13 04:50:18,640 INFO o.a.j.JMeter: Running test (1513137018640)
|
||||||
|
2017-12-13 04:50:18,728 INFO o.a.j.e.StandardJMeterEngine: Starting ThreadGroup: 1 : Thread Group
|
||||||
|
2017-12-13 04:50:18,737 INFO o.a.j.e.StandardJMeterEngine: Starting 5 threads for group Thread Group.
|
||||||
|
2017-12-13 04:50:18,737 INFO o.a.j.e.StandardJMeterEngine: Thread will continue on error
|
||||||
|
2017-12-13 04:50:18,738 INFO o.a.j.t.ThreadGroup: Starting thread group... number=1 threads=5 ramp-up=1 perThread=200.0 delayedStart=false
|
||||||
|
2017-12-13 04:50:18,751 INFO o.a.j.t.JMeterThread: Thread started: Thread Group 1-1
|
||||||
|
2017-12-13 04:50:18,753 INFO o.a.j.t.ThreadGroup: Started thread group number 1
|
||||||
|
2017-12-13 04:50:18,753 INFO o.a.j.e.StandardJMeterEngine: All thread groups have been started
|
||||||
|
2017-12-13 04:50:18,786 INFO o.a.j.p.h.s.HTTPHCAbstractImpl: Local host = MBP
|
||||||
|
2017-12-13 04:50:18,797 INFO o.a.j.p.h.s.HTTPHC4Impl: HTTP request retry count = 0
|
||||||
|
2017-12-13 04:50:18,812 INFO o.a.j.s.SampleResult: Note: Sample TimeStamps are START times
|
||||||
|
2017-12-13 04:50:18,812 INFO o.a.j.s.SampleResult: sampleresult.default.encoding is set to ISO-8859-1
|
||||||
|
2017-12-13 04:50:18,812 INFO o.a.j.s.SampleResult: sampleresult.useNanoTime=true
|
||||||
|
2017-12-13 04:50:18,812 INFO o.a.j.s.SampleResult: sampleresult.nanoThreadSleep=5000
|
||||||
|
2017-12-13 04:50:18,954 INFO o.a.j.t.JMeterThread: Thread started: Thread Group 1-2
|
||||||
|
2017-12-13 04:50:19,152 INFO o.a.j.t.JMeterThread: Thread started: Thread Group 1-3
|
||||||
|
2017-12-13 04:50:19,257 INFO o.a.j.t.JMeterThread: Thread is done: Thread Group 1-3
|
||||||
|
2017-12-13 04:50:19,257 INFO o.a.j.t.JMeterThread: Thread finished: Thread Group 1-3
|
||||||
|
2017-12-13 04:50:19,264 INFO o.a.j.t.JMeterThread: Thread is done: Thread Group 1-2
|
||||||
|
2017-12-13 04:50:19,264 INFO o.a.j.t.JMeterThread: Thread is done: Thread Group 1-1
|
||||||
|
2017-12-13 04:50:19,264 INFO o.a.j.t.JMeterThread: Thread finished: Thread Group 1-2
|
||||||
|
2017-12-13 04:50:19,265 INFO o.a.j.t.JMeterThread: Thread finished: Thread Group 1-1
|
||||||
|
2017-12-13 04:50:19,353 INFO o.a.j.t.JMeterThread: Thread started: Thread Group 1-4
|
||||||
|
2017-12-13 04:50:19,365 INFO o.a.j.t.JMeterThread: Thread is done: Thread Group 1-4
|
||||||
|
2017-12-13 04:50:19,365 INFO o.a.j.t.JMeterThread: Thread finished: Thread Group 1-4
|
||||||
|
2017-12-13 04:50:19,557 INFO o.a.j.t.JMeterThread: Thread started: Thread Group 1-5
|
||||||
|
2017-12-13 04:50:19,573 INFO o.a.j.t.JMeterThread: Thread is done: Thread Group 1-5
|
||||||
|
2017-12-13 04:50:19,573 INFO o.a.j.t.JMeterThread: Thread finished: Thread Group 1-5
|
||||||
|
2017-12-13 04:50:19,573 INFO o.a.j.e.StandardJMeterEngine: Notifying test listeners of end of test
|
||||||
|
2017-12-13 04:50:19,575 INFO o.a.j.r.Summariser: summary = 5 in 00:00:01 = 5.4/s Avg: 155 Min: 10 Max: 388 Err: 4 (80.00%)
|
|
@ -0,0 +1,69 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>jmeter</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>jmeter</name>
|
||||||
|
<description>Intro to Performance testing using JMeter</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<artifactId>parent-boot-5</artifactId>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../parent-boot-5</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<jmeter.version>2.6.0</jmeter.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-mongodb</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-rest</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.lazerycode.jmeter</groupId>
|
||||||
|
<artifactId>jmeter-maven-plugin</artifactId>
|
||||||
|
<version>${jmeter.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>jmeter-tests</id>
|
||||||
|
<goals>
|
||||||
|
<goal>jmeter</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<testFilesDirectory>${project.basedir}/src/main/resources</testFilesDirectory>
|
||||||
|
<resultsDirectory>${project.basedir}/src/main/resources</resultsDirectory>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
|
@ -0,0 +1,6 @@
|
||||||
|
timeStamp,elapsed,label,responseCode,responseMessage,threadName,dataType,success,failureMessage,bytes,sentBytes,grpThreads,allThreads,Latency,IdleTime,Connect
|
||||||
|
1513134869133,1075,HTTP Request,Non HTTP response code: java.net.ConnectException,Non HTTP response message: Connection refused (Connection refused),Thread Group 1-4,text,false,"The operation lasted too long: It took 1,075 milliseconds, but should not have lasted longer than 10 milliseconds.",2058,0,5,5,0,0,1075
|
||||||
|
1513134869272,935,HTTP Request,Non HTTP response code: java.net.ConnectException,Non HTTP response message: Connection refused (Connection refused),Thread Group 1-1,text,false,"The operation lasted too long: It took 935 milliseconds, but should not have lasted longer than 10 milliseconds.",2058,0,5,5,0,0,935
|
||||||
|
1513134869133,1075,HTTP Request,Non HTTP response code: java.net.ConnectException,Non HTTP response message: Connection refused (Connection refused),Thread Group 1-3,text,false,"The operation lasted too long: It took 1,075 milliseconds, but should not have lasted longer than 10 milliseconds.",2058,0,5,5,0,0,1075
|
||||||
|
1513134869272,935,HTTP Request,Non HTTP response code: java.net.ConnectException,Non HTTP response message: Connection refused (Connection refused),Thread Group 1-2,text,false,"The operation lasted too long: It took 935 milliseconds, but should not have lasted longer than 10 milliseconds.",2058,0,5,5,0,0,934
|
||||||
|
1513134869133,1074,HTTP Request,Non HTTP response code: java.net.ConnectException,Non HTTP response message: Connection refused (Connection refused),Thread Group 1-5,text,false,"The operation lasted too long: It took 1,074 milliseconds, but should not have lasted longer than 10 milliseconds.",2058,0,5,5,0,0,1074
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<jmeterTestPlan version="1.2" properties="3.2" jmeter="3.3 r1808647">
|
<jmeterTestPlan version="1.2" properties="3.2" jmeter="3.3 r1808647">
|
||||||
<hashTree>
|
<hashTree>
|
||||||
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="JMeter Jenkins" enabled="true">
|
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="JMeter" enabled="true">
|
||||||
<stringProp name="TestPlan.comments"></stringProp>
|
<stringProp name="TestPlan.comments"></stringProp>
|
||||||
<boolProp name="TestPlan.functional_mode">false</boolProp>
|
<boolProp name="TestPlan.functional_mode">false</boolProp>
|
||||||
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
|
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<testResults version="1.2">
|
||||||
|
<httpSample t="83" it="0" lt="81" ct="1" ts="1513137019153" s="false" lb="HTTP Request" rc="200" rm="" tn="Thread Group 1-3" dt="text" by="502" sby="126" ng="3" na="3">
|
||||||
|
<assertionResult>
|
||||||
|
<name>Duration Assertion</name>
|
||||||
|
<failure>true</failure>
|
||||||
|
<error>false</error>
|
||||||
|
<failureMessage>The operation lasted too long: It took 83 milliseconds, but should not have lasted longer than 10 milliseconds.</failureMessage>
|
||||||
|
</assertionResult>
|
||||||
|
</httpSample>
|
||||||
|
<httpSample t="388" it="0" lt="382" ct="292" ts="1513137018851" s="false" lb="HTTP Request" rc="200" rm="" tn="Thread Group 1-1" dt="text" by="502" sby="126" ng="3" na="3">
|
||||||
|
<assertionResult>
|
||||||
|
<name>Duration Assertion</name>
|
||||||
|
<failure>true</failure>
|
||||||
|
<error>false</error>
|
||||||
|
<failureMessage>The operation lasted too long: It took 388 milliseconds, but should not have lasted longer than 10 milliseconds.</failureMessage>
|
||||||
|
</assertionResult>
|
||||||
|
</httpSample>
|
||||||
|
<httpSample t="281" it="0" lt="279" ct="189" ts="1513137018955" s="false" lb="HTTP Request" rc="200" rm="" tn="Thread Group 1-2" dt="text" by="502" sby="126" ng="3" na="3">
|
||||||
|
<assertionResult>
|
||||||
|
<name>Duration Assertion</name>
|
||||||
|
<failure>true</failure>
|
||||||
|
<error>false</error>
|
||||||
|
<failureMessage>The operation lasted too long: It took 281 milliseconds, but should not have lasted longer than 10 milliseconds.</failureMessage>
|
||||||
|
</assertionResult>
|
||||||
|
</httpSample>
|
||||||
|
<httpSample t="10" it="0" lt="10" ct="1" ts="1513137019354" s="true" lb="HTTP Request" rc="200" rm="" tn="Thread Group 1-4" dt="text" by="502" sby="126" ng="1" na="1">
|
||||||
|
<assertionResult>
|
||||||
|
<name>Duration Assertion</name>
|
||||||
|
<failure>false</failure>
|
||||||
|
<error>false</error>
|
||||||
|
</assertionResult>
|
||||||
|
</httpSample>
|
||||||
|
<httpSample t="13" it="0" lt="13" ct="1" ts="1513137019558" s="false" lb="HTTP Request" rc="200" rm="" tn="Thread Group 1-5" dt="text" by="502" sby="126" ng="1" na="1">
|
||||||
|
<assertionResult>
|
||||||
|
<name>Duration Assertion</name>
|
||||||
|
<failure>true</failure>
|
||||||
|
<error>false</error>
|
||||||
|
<failureMessage>The operation lasted too long: It took 13 milliseconds, but should not have lasted longer than 10 milliseconds.</failureMessage>
|
||||||
|
</assertionResult>
|
||||||
|
</httpSample>
|
||||||
|
|
||||||
|
</testResults>
|
|
@ -1 +1,4 @@
|
||||||
## JSON B
|
## JSON B
|
||||||
|
|
||||||
|
## Relevant articles:
|
||||||
|
- [Introduction to the JSON Binding API (JSR 367) in Java](http://www.baeldung.com/java-json-binding-api)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
## Relevant articles:
|
||||||
|
- [The Order of Tests in JUnit](http://www.baeldung.com/junit-5-test-order)
|
|
@ -630,13 +630,30 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.http-client</groupId>
|
<groupId>com.google.http-client</groupId>
|
||||||
<artifactId>google-http-client-jackson2</artifactId>
|
<artifactId>google-http-client-jackson2</artifactId>
|
||||||
<version>${googleclient.version}</version>
|
<version>${googleclient.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.http-client</groupId>
|
<groupId>com.google.http-client</groupId>
|
||||||
<artifactId>google-http-client-gson</artifactId>
|
<artifactId>google-http-client-gson</artifactId>
|
||||||
<version>${googleclient.version}</version>
|
<version>${googleclient.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- google api -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.api-client</groupId>
|
||||||
|
<artifactId>google-api-client</artifactId>
|
||||||
|
<version>${google-api.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.oauth-client</groupId>
|
||||||
|
<artifactId>google-oauth-client-jetty</artifactId>
|
||||||
|
<version>${google-api.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.apis</groupId>
|
||||||
|
<artifactId>google-api-services-sheets</artifactId>
|
||||||
|
<version>${google-sheets.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
|
@ -710,5 +727,7 @@
|
||||||
<cache.version>1.0.0</cache.version>
|
<cache.version>1.0.0</cache.version>
|
||||||
<hazelcast.version>3.8.4</hazelcast.version>
|
<hazelcast.version>3.8.4</hazelcast.version>
|
||||||
<caffeine.version>2.5.5</caffeine.version>
|
<caffeine.version>2.5.5</caffeine.version>
|
||||||
|
<google-api.version>1.23.0</google-api.version>
|
||||||
|
<google-sheets.version>v4-rev493-1.21.0</google-sheets.version>
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.baeldung.google.sheets;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.api.client.auth.oauth2.Credential;
|
||||||
|
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
|
||||||
|
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
|
||||||
|
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
|
||||||
|
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
|
||||||
|
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
|
||||||
|
import com.google.api.client.json.jackson2.JacksonFactory;
|
||||||
|
import com.google.api.client.util.store.MemoryDataStoreFactory;
|
||||||
|
import com.google.api.services.sheets.v4.SheetsScopes;
|
||||||
|
|
||||||
|
public class GoogleAuthorizeUtil {
|
||||||
|
public static Credential authorize() throws IOException, GeneralSecurityException {
|
||||||
|
InputStream in = GoogleAuthorizeUtil.class.getResourceAsStream("/google-sheets-client-secret.json");
|
||||||
|
GoogleClientSecrets clientSecrets = GoogleClientSecrets
|
||||||
|
.load(JacksonFactory.getDefaultInstance(), new InputStreamReader(in));
|
||||||
|
|
||||||
|
List<String> scopes = Arrays.asList(SheetsScopes.SPREADSHEETS);
|
||||||
|
|
||||||
|
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow
|
||||||
|
.Builder(GoogleNetHttpTransport.newTrustedTransport(),
|
||||||
|
JacksonFactory.getDefaultInstance(),
|
||||||
|
clientSecrets,
|
||||||
|
scopes)
|
||||||
|
.setDataStoreFactory(new MemoryDataStoreFactory())
|
||||||
|
.setAccessType("offline")
|
||||||
|
.build();
|
||||||
|
Credential credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver())
|
||||||
|
.authorize("user");
|
||||||
|
|
||||||
|
return credential;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.baeldung.google.sheets;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
|
||||||
|
import com.google.api.client.auth.oauth2.Credential;
|
||||||
|
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
|
||||||
|
import com.google.api.client.json.jackson2.JacksonFactory;
|
||||||
|
import com.google.api.services.sheets.v4.Sheets;
|
||||||
|
|
||||||
|
public class SheetsServiceUtil {
|
||||||
|
|
||||||
|
private static final String APPLICATION_NAME = "Google Sheets Example";
|
||||||
|
|
||||||
|
public static Sheets getSheetsService() throws IOException, GeneralSecurityException {
|
||||||
|
Credential credential = GoogleAuthorizeUtil.authorize();
|
||||||
|
return new Sheets.Builder(GoogleNetHttpTransport.newTrustedTransport(),
|
||||||
|
JacksonFactory.getDefaultInstance(), credential)
|
||||||
|
.setApplicationName(APPLICATION_NAME)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
{"installed":{"client_id":"394827218507-2ev02b2ha8plt7g2lh5nqse02ee737cf.apps.googleusercontent.com","project_id":"decisive-octane-187810","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"2MnN1DfenoCGWMay3v8Bf7eI","redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}}
|
|
@ -0,0 +1,140 @@
|
||||||
|
package com.baeldung.google.sheets;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.google.api.services.sheets.v4.Sheets;
|
||||||
|
import com.google.api.services.sheets.v4.model.AppendValuesResponse;
|
||||||
|
import com.google.api.services.sheets.v4.model.BatchGetValuesResponse;
|
||||||
|
import com.google.api.services.sheets.v4.model.BatchUpdateSpreadsheetRequest;
|
||||||
|
import com.google.api.services.sheets.v4.model.BatchUpdateValuesRequest;
|
||||||
|
import com.google.api.services.sheets.v4.model.BatchUpdateValuesResponse;
|
||||||
|
import com.google.api.services.sheets.v4.model.CopyPasteRequest;
|
||||||
|
import com.google.api.services.sheets.v4.model.GridRange;
|
||||||
|
import com.google.api.services.sheets.v4.model.Request;
|
||||||
|
import com.google.api.services.sheets.v4.model.Spreadsheet;
|
||||||
|
import com.google.api.services.sheets.v4.model.SpreadsheetProperties;
|
||||||
|
import com.google.api.services.sheets.v4.model.UpdateSpreadsheetPropertiesRequest;
|
||||||
|
import com.google.api.services.sheets.v4.model.UpdateValuesResponse;
|
||||||
|
import com.google.api.services.sheets.v4.model.ValueRange;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.*;
|
||||||
|
|
||||||
|
public class GoogleSheetsIntegrationTest {
|
||||||
|
|
||||||
|
private static Sheets sheetsService;
|
||||||
|
|
||||||
|
// this id can be replaced with your spreadsheet id
|
||||||
|
// otherwise be advised that multiple people may run this test and update the public spreadsheet
|
||||||
|
private static final String SPREADSHEET_ID = "1sILuxZUnyl_7-MlNThjt765oWshN3Xs-PPLfqYe4DhI";
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setup() throws GeneralSecurityException, IOException {
|
||||||
|
sheetsService = SheetsServiceUtil.getSheetsService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenWriteSheet_thenReadSheetOk() throws IOException {
|
||||||
|
ValueRange body = new ValueRange()
|
||||||
|
.setValues(Arrays.asList(
|
||||||
|
Arrays.asList("Expenses January"),
|
||||||
|
Arrays.asList("books", "30"),
|
||||||
|
Arrays.asList("pens", "10"),
|
||||||
|
Arrays.asList("Expenses February"),
|
||||||
|
Arrays.asList("clothes", "20"),
|
||||||
|
Arrays.asList("shoes", "5")));
|
||||||
|
UpdateValuesResponse result = sheetsService.spreadsheets().values()
|
||||||
|
.update(SPREADSHEET_ID, "A1", body)
|
||||||
|
.setValueInputOption("RAW")
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
List<ValueRange> data = new ArrayList<>();
|
||||||
|
data.add(new ValueRange()
|
||||||
|
.setRange("D1")
|
||||||
|
.setValues(Arrays.asList(
|
||||||
|
Arrays.asList("January Total", "=B2+B3"))));
|
||||||
|
data.add(new ValueRange()
|
||||||
|
.setRange("D4")
|
||||||
|
.setValues(Arrays.asList(
|
||||||
|
Arrays.asList("February Total", "=B5+B6"))));
|
||||||
|
|
||||||
|
BatchUpdateValuesRequest batchBody = new BatchUpdateValuesRequest()
|
||||||
|
.setValueInputOption("USER_ENTERED")
|
||||||
|
.setData(data);
|
||||||
|
BatchUpdateValuesResponse batchResult =
|
||||||
|
sheetsService.spreadsheets().values()
|
||||||
|
.batchUpdate(SPREADSHEET_ID, batchBody)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
List<String> ranges = Arrays.asList("E1","E4");
|
||||||
|
BatchGetValuesResponse readResult =
|
||||||
|
sheetsService.spreadsheets().values()
|
||||||
|
.batchGet(SPREADSHEET_ID)
|
||||||
|
.setRanges(ranges)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
ValueRange januaryTotal = readResult.getValueRanges().get(0);
|
||||||
|
assertThat(januaryTotal.getValues().get(0).get(0)).isEqualTo("40");
|
||||||
|
|
||||||
|
ValueRange febTotal = readResult.getValueRanges().get(1);
|
||||||
|
assertThat(febTotal.getValues().get(0).get(0)).isEqualTo("25");
|
||||||
|
|
||||||
|
ValueRange appendBody = new ValueRange()
|
||||||
|
.setValues(Arrays.asList(
|
||||||
|
Arrays.asList("Total", "=E1+E4")));
|
||||||
|
AppendValuesResponse appendResult =
|
||||||
|
sheetsService.spreadsheets().values()
|
||||||
|
.append(SPREADSHEET_ID, "A1", appendBody)
|
||||||
|
.setValueInputOption("USER_ENTERED")
|
||||||
|
.setInsertDataOption("INSERT_ROWS")
|
||||||
|
.setIncludeValuesInResponse(true)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
ValueRange total = appendResult.getUpdates().getUpdatedData();
|
||||||
|
assertThat(total.getValues().get(0).get(1)).isEqualTo("65");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenUpdateSpreadSheetTitle_thenOk() throws IOException {
|
||||||
|
|
||||||
|
UpdateSpreadsheetPropertiesRequest updateRequest = new UpdateSpreadsheetPropertiesRequest()
|
||||||
|
.setFields("*")
|
||||||
|
.setProperties(new SpreadsheetProperties().setTitle("Expenses"));
|
||||||
|
|
||||||
|
CopyPasteRequest copyRequest = new CopyPasteRequest()
|
||||||
|
.setSource(new GridRange().setSheetId(0)
|
||||||
|
.setStartColumnIndex(0).setEndColumnIndex(2)
|
||||||
|
.setStartRowIndex(0).setEndRowIndex(1))
|
||||||
|
.setDestination(new GridRange().setSheetId(1)
|
||||||
|
.setStartColumnIndex(0).setEndColumnIndex(2)
|
||||||
|
.setStartRowIndex(0).setEndRowIndex(1))
|
||||||
|
.setPasteType("PASTE_VALUES");
|
||||||
|
|
||||||
|
List<Request> requests = new ArrayList<>();
|
||||||
|
|
||||||
|
requests.add(new Request().setCopyPaste(copyRequest));
|
||||||
|
requests.add(new Request().setUpdateSpreadsheetProperties(updateRequest));
|
||||||
|
|
||||||
|
BatchUpdateSpreadsheetRequest body =
|
||||||
|
new BatchUpdateSpreadsheetRequest().setRequests(requests);
|
||||||
|
|
||||||
|
sheetsService.spreadsheets().batchUpdate(SPREADSHEET_ID, body).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCreateSpreadSheet_thenIdOk() throws IOException {
|
||||||
|
Spreadsheet spreadSheet = new Spreadsheet()
|
||||||
|
.setProperties(new SpreadsheetProperties().setTitle("My Spreadsheet"));
|
||||||
|
Spreadsheet result = sheetsService.spreadsheets().create(spreadSheet).execute();
|
||||||
|
|
||||||
|
assertThat(result.getSpreadsheetId()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import org.neuroph.core.NeuralNetwork;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class XORTest {
|
public class XORIntegrationTest {
|
||||||
private NeuralNetwork ann = null;
|
private NeuralNetwork ann = null;
|
||||||
|
|
||||||
private void print(String input, double output, double actual) {
|
private void print(String input, double output, double actual) {
|
|
@ -86,6 +86,9 @@ org.eclipse.osgi_3.12.1.v20170821-1548.jar
|
||||||
|
|
||||||
= = NOT GOOD = =
|
= = NOT GOOD = =
|
||||||
|
|
||||||
|
## Relevant articles:
|
||||||
|
- [Introduction to OSGi](http://www.baeldung.com/osgi)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
###Relevant Articles:
|
###Relevant Articles:
|
||||||
- [A Guide to the Front Controller Pattern in Java](http://www.baeldung.com/java-front-controller-pattern)
|
- [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)
|
- [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)
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
- [Deleting Objects with Hibernate](http://www.baeldung.com/delete-with-hibernate)
|
- [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)
|
- [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)
|
- [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
|
### Eclipse Config
|
||||||
After importing the project into Eclipse, you may see the following error:
|
After importing the project into Eclipse, you may see the following error:
|
||||||
|
|
10
pom.xml
10
pom.xml
|
@ -49,8 +49,6 @@
|
||||||
<module>core-java-8</module>
|
<module>core-java-8</module>
|
||||||
<module>core-java-concurrency</module>
|
<module>core-java-concurrency</module>
|
||||||
<module>couchbase</module>
|
<module>couchbase</module>
|
||||||
<module>cas/cas-server</module>
|
|
||||||
<module>cas/cas-secured-app</module>
|
|
||||||
|
|
||||||
<module>deltaspike</module>
|
<module>deltaspike</module>
|
||||||
<module>dozer</module>
|
<module>dozer</module>
|
||||||
|
@ -60,7 +58,6 @@
|
||||||
<!--<module>ejb</module>-->
|
<!--<module>ejb</module>-->
|
||||||
|
|
||||||
<module>feign</module>
|
<module>feign</module>
|
||||||
<module>flyway</module>
|
|
||||||
|
|
||||||
<!-- <module>testing-modules/gatling</module> --> <!-- not meant to run as part of the standard build -->
|
<!-- <module>testing-modules/gatling</module> --> <!-- not meant to run as part of the standard build -->
|
||||||
|
|
||||||
|
@ -141,8 +138,8 @@
|
||||||
<module>persistence-modules/solr</module>
|
<module>persistence-modules/solr</module>
|
||||||
<module>spark-java</module>
|
<module>spark-java</module>
|
||||||
<!-- <module>spring-5</module>-->
|
<!-- <module>spring-5</module>-->
|
||||||
|
<module>spring-5-reactive</module>
|
||||||
<module>spring-5-mvc</module>
|
<module>spring-5-mvc</module>
|
||||||
<module>spring-acl</module>
|
|
||||||
<module>spring-activiti</module>
|
<module>spring-activiti</module>
|
||||||
<module>spring-akka</module>
|
<module>spring-akka</module>
|
||||||
<module>spring-amqp</module>
|
<module>spring-amqp</module>
|
||||||
|
@ -152,7 +149,7 @@
|
||||||
<module>spring-batch</module>
|
<module>spring-batch</module>
|
||||||
<module>spring-bom</module>
|
<module>spring-bom</module>
|
||||||
<module>spring-boot</module>
|
<module>spring-boot</module>
|
||||||
<module>spring-boot-keycloak</module>
|
<module>spring-boot-keycloak</module>
|
||||||
<module>spring-boot-bootstrap</module>
|
<module>spring-boot-bootstrap</module>
|
||||||
<module>spring-cloud-data-flow</module>
|
<module>spring-cloud-data-flow</module>
|
||||||
<module>spring-cloud</module>
|
<module>spring-cloud</module>
|
||||||
|
@ -175,8 +172,9 @@
|
||||||
<module>spring-hibernate4</module>
|
<module>spring-hibernate4</module>
|
||||||
<module>persistence-modules/spring-hibernate-5</module>
|
<module>persistence-modules/spring-hibernate-5</module>
|
||||||
<module>spring-integration</module>
|
<module>spring-integration</module>
|
||||||
|
<module>spring-jenkins-pipeline</module>
|
||||||
<module>spring-jersey</module>
|
<module>spring-jersey</module>
|
||||||
<module>spring-jmeter-jenkins</module>
|
<module>jmeter</module>
|
||||||
<module>spring-jms</module>
|
<module>spring-jms</module>
|
||||||
<module>spring-jooq</module>
|
<module>spring-jooq</module>
|
||||||
<module>persistence-modules/spring-jpa</module>
|
<module>persistence-modules/spring-jpa</module>
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#folders#
|
||||||
|
.idea
|
||||||
|
/target
|
||||||
|
/neoDb*
|
||||||
|
/data
|
||||||
|
/src/main/webapp/WEB-INF/classes
|
||||||
|
*/META-INF/*
|
||||||
|
|
||||||
|
# Packaged files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.ear
|
|
@ -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)
|
|
@ -0,0 +1,201 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>spring-5-reactive-client</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>spring-5</name>
|
||||||
|
<description>spring 5 sample project about new features</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.0.0.M7</version>
|
||||||
|
<relativePath /> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectreactor</groupId>
|
||||||
|
<artifactId>reactor-spring</artifactId>
|
||||||
|
<version>${reactor-spring.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.json.bind</groupId>
|
||||||
|
<artifactId>javax.json.bind-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Dependencies for Yasson -->
|
||||||
|
<!-- <dependency> -->
|
||||||
|
<!-- <groupId>org.eclipse</groupId> -->
|
||||||
|
<!-- <artifactId>yasson</artifactId> -->
|
||||||
|
<!-- <version>1.0</version> -->
|
||||||
|
<!-- </dependency> -->
|
||||||
|
<!-- <dependency> -->
|
||||||
|
<!-- <groupId>org.glassfish</groupId> -->
|
||||||
|
<!-- <artifactId>javax.json</artifactId> -->
|
||||||
|
<!-- <version>1.1.2</version> -->
|
||||||
|
<!-- </dependency> -->
|
||||||
|
<!-- Dependencies for Johnzon -->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.geronimo.specs</groupId>
|
||||||
|
<artifactId>geronimo-json_1.1_spec</artifactId>
|
||||||
|
<version>${geronimo-json_1.1_spec.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.johnzon</groupId>
|
||||||
|
<artifactId>johnzon-jsonb</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- utils -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- runtime and test scoped -->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-test</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-collections4</artifactId>
|
||||||
|
<version>4.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.platform</groupId>
|
||||||
|
<artifactId>junit-platform-surefire-provider</artifactId>
|
||||||
|
<version>${junit.platform.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.platform</groupId>
|
||||||
|
<artifactId>junit-platform-runner</artifactId>
|
||||||
|
<version>${junit.platform.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<mainClass>com.baeldung.Spring5Application</mainClass>
|
||||||
|
<layout>JAR</layout>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<forkCount>3</forkCount>
|
||||||
|
<reuseForks>true</reuseForks>
|
||||||
|
<parallel>methods</parallel>
|
||||||
|
<useUnlimitedThreads>true</useUnlimitedThreads>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/*IntegrationTest.java</exclude>
|
||||||
|
<exclude>**/*LiveTest.java</exclude>
|
||||||
|
</excludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>spring-milestones</id>
|
||||||
|
<name>Spring Milestones</name>
|
||||||
|
<url>https://repo.spring.io/milestone</url>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
<pluginRepositories>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>spring-milestones</id>
|
||||||
|
<name>Spring Milestones</name>
|
||||||
|
<url>https://repo.spring.io/milestone</url>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</pluginRepository>
|
||||||
|
</pluginRepositories>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<junit.platform.version>1.0.0</junit.platform.version>
|
||||||
|
<junit.jupiter.version>5.0.0</junit.jupiter.version>
|
||||||
|
<maven-surefire-plugin.version>2.20</maven-surefire-plugin.version>
|
||||||
|
<spring.version>5.0.1.RELEASE</spring.version>
|
||||||
|
<reactor-spring.version>1.0.1.RELEASE</reactor-spring.version>
|
||||||
|
<johnzon.version>1.1.3</johnzon.version>
|
||||||
|
<jsonb-api.version>1.0</jsonb-api.version>
|
||||||
|
<geronimo-json_1.1_spec.version>1.0</geronimo-json_1.1_spec.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
logging.level.root=INFO
|
||||||
|
|
||||||
|
server.port=8081
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||||
|
# Pattern of log message for console appender
|
||||||
|
<Pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n</Pattern>
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<logger name="org.springframework" level="INFO" />
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="stdout" />
|
||||||
|
</root>
|
||||||
|
|
||||||
|
</configuration>
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
|
||||||
|
version="3.1">
|
||||||
|
|
||||||
|
<display-name>Spring Functional Application</display-name>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>functional</servlet-name>
|
||||||
|
<servlet-class>com.baeldung.functional.RootServlet</servlet-class>
|
||||||
|
<load-on-startup>1</load-on-startup>
|
||||||
|
<async-supported>true</async-supported>
|
||||||
|
</servlet>
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>functional</servlet-name>
|
||||||
|
<url-pattern>/</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
|
||||||
|
</web-app>
|
|
@ -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<ClientResponse> 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||||
|
# Pattern of log message for console appender
|
||||||
|
<Pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n</Pattern>
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<logger name="org.springframework" level="INFO" />
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="stdout" />
|
||||||
|
</root>
|
||||||
|
|
||||||
|
</configuration>
|
|
@ -0,0 +1,12 @@
|
||||||
|
#folders#
|
||||||
|
.idea
|
||||||
|
/target
|
||||||
|
/neoDb*
|
||||||
|
/data
|
||||||
|
/src/main/webapp/WEB-INF/classes
|
||||||
|
*/META-INF/*
|
||||||
|
|
||||||
|
# Packaged files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.ear
|
|
@ -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)
|
|
@ -0,0 +1,201 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>spring-5-reactive</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>spring-5</name>
|
||||||
|
<description>spring 5 sample project about new features</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.0.0.M7</version>
|
||||||
|
<relativePath /> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectreactor</groupId>
|
||||||
|
<artifactId>reactor-spring</artifactId>
|
||||||
|
<version>${reactor-spring.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.json.bind</groupId>
|
||||||
|
<artifactId>javax.json.bind-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Dependencies for Yasson -->
|
||||||
|
<!-- <dependency> -->
|
||||||
|
<!-- <groupId>org.eclipse</groupId> -->
|
||||||
|
<!-- <artifactId>yasson</artifactId> -->
|
||||||
|
<!-- <version>1.0</version> -->
|
||||||
|
<!-- </dependency> -->
|
||||||
|
<!-- <dependency> -->
|
||||||
|
<!-- <groupId>org.glassfish</groupId> -->
|
||||||
|
<!-- <artifactId>javax.json</artifactId> -->
|
||||||
|
<!-- <version>1.1.2</version> -->
|
||||||
|
<!-- </dependency> -->
|
||||||
|
<!-- Dependencies for Johnzon -->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.geronimo.specs</groupId>
|
||||||
|
<artifactId>geronimo-json_1.1_spec</artifactId>
|
||||||
|
<version>${geronimo-json_1.1_spec.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.johnzon</groupId>
|
||||||
|
<artifactId>johnzon-jsonb</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- utils -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- runtime and test scoped -->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-test</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-collections4</artifactId>
|
||||||
|
<version>4.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.platform</groupId>
|
||||||
|
<artifactId>junit-platform-surefire-provider</artifactId>
|
||||||
|
<version>${junit.platform.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.platform</groupId>
|
||||||
|
<artifactId>junit-platform-runner</artifactId>
|
||||||
|
<version>${junit.platform.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<mainClass>com.baeldung.Spring5Application</mainClass>
|
||||||
|
<layout>JAR</layout>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<forkCount>3</forkCount>
|
||||||
|
<reuseForks>true</reuseForks>
|
||||||
|
<parallel>methods</parallel>
|
||||||
|
<useUnlimitedThreads>true</useUnlimitedThreads>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/*IntegrationTest.java</exclude>
|
||||||
|
<exclude>**/*LiveTest.java</exclude>
|
||||||
|
</excludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>spring-milestones</id>
|
||||||
|
<name>Spring Milestones</name>
|
||||||
|
<url>https://repo.spring.io/milestone</url>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
<pluginRepositories>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>spring-milestones</id>
|
||||||
|
<name>Spring Milestones</name>
|
||||||
|
<url>https://repo.spring.io/milestone</url>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</pluginRepository>
|
||||||
|
</pluginRepositories>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<junit.platform.version>1.0.0</junit.platform.version>
|
||||||
|
<junit.jupiter.version>5.0.0</junit.jupiter.version>
|
||||||
|
<maven-surefire-plugin.version>2.20</maven-surefire-plugin.version>
|
||||||
|
<spring.version>5.0.1.RELEASE</spring.version>
|
||||||
|
<reactor-spring.version>1.0.1.RELEASE</reactor-spring.version>
|
||||||
|
<johnzon.version>1.1.3</johnzon.version>
|
||||||
|
<jsonb-api.version>1.0</jsonb-api.version>
|
||||||
|
<geronimo-json_1.1_spec.version>1.0</geronimo-json_1.1_spec.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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<Foo> getFoo(@PathVariable("id") long id) {
|
||||||
|
return Mono.just(new Foo(id, randomAlphabetic(6)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE, value = "/foos")
|
||||||
|
public Flux<Foo> getAllFoos2() {
|
||||||
|
final Flux<Foo> foosFlux = Flux.fromStream(Stream.generate(() -> new Foo(new Random().nextLong(), randomAlphabetic(6))));
|
||||||
|
final Flux<Long> 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<Foo> getAllFoos() {
|
||||||
|
final Flux<Foo> flux = Flux.<Foo> create(fluxSink -> {
|
||||||
|
while (true) {
|
||||||
|
fluxSink.next(new Foo(new Random().nextLong(), randomAlphabetic(6)));
|
||||||
|
}
|
||||||
|
}).sample(Duration.ofSeconds(1)).log();
|
||||||
|
|
||||||
|
return flux;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
logging.level.root=INFO
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
|
||||||
|
version="3.1">
|
||||||
|
|
||||||
|
<display-name>Spring Functional Application</display-name>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>functional</servlet-name>
|
||||||
|
<servlet-class>com.baeldung.functional.RootServlet</servlet-class>
|
||||||
|
<load-on-startup>1</load-on-startup>
|
||||||
|
<async-supported>true</async-supported>
|
||||||
|
</servlet>
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>functional</servlet-name>
|
||||||
|
<url-pattern>/</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
|
||||||
|
</web-app>
|
|
@ -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<Foo> flux = Flux.<Foo> create(fluxSink -> {
|
||||||
|
while (true) {
|
||||||
|
fluxSink.next(new Foo(new Random().nextLong(), randomAlphabetic(6)));
|
||||||
|
}
|
||||||
|
}).sample(Duration.ofSeconds(1)).log();
|
||||||
|
|
||||||
|
flux.subscribe();
|
||||||
|
|
||||||
|
assertNotNull(flux);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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 WebClient](http://www.baeldung.com/spring-5-webclient)
|
||||||
- [Spring 5 Functional Bean Registration](http://www.baeldung.com/spring-5-functional-beans)
|
- [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)
|
- [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)
|
||||||
|
|
|
@ -2,7 +2,6 @@ package com.baeldung.web;
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<groupId>com.baeldung</groupId>
|
|
||||||
<artifactId>spring-acl</artifactId>
|
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
|
||||||
<packaging>war</packaging>
|
|
||||||
|
|
||||||
<name>spring-acl</name>
|
|
||||||
<description>Spring ACL</description>
|
|
||||||
|
|
||||||
<parent>
|
|
||||||
<artifactId>parent-boot-5</artifactId>
|
|
||||||
<groupId>com.baeldung</groupId>
|
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
|
||||||
<relativePath>../parent-boot-5</relativePath>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.h2database</groupId>
|
|
||||||
<artifactId>h2</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.security</groupId>
|
|
||||||
<artifactId>spring-security-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.security</groupId>
|
|
||||||
<artifactId>spring-security-acl</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.security</groupId>
|
|
||||||
<artifactId>spring-security-config</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-context-support</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.sf.ehcache</groupId>
|
|
||||||
<artifactId>ehcache-core</artifactId>
|
|
||||||
<version>2.6.11</version>
|
|
||||||
<type>jar</type>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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 {
|
|
||||||
|
|
||||||
}
|
|
|
@ -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<NoticeMessage, Long>{
|
|
||||||
|
|
||||||
@PostFilter("hasPermission(filterObject, 'READ')")
|
|
||||||
List<NoticeMessage> findAll();
|
|
||||||
|
|
||||||
@PostAuthorize("hasPermission(returnObject, 'READ')")
|
|
||||||
NoticeMessage findById(Integer id);
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@PreAuthorize("hasPermission(#noticeMessage, 'WRITE')")
|
|
||||||
NoticeMessage save(@Param("noticeMessage")NoticeMessage noticeMessage);
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
;
|
|
|
@ -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);
|
|
|
@ -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
|
|
|
@ -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<NoticeMessage> 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<NoticeMessage> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,4 +2,5 @@
|
||||||
|
|
||||||
- [Implementing a Custom Spring AOP Annotation](http://www.baeldung.com/spring-aop-annotation)
|
- [Implementing a Custom Spring AOP Annotation](http://www.baeldung.com/spring-aop-annotation)
|
||||||
- [Intro to AspectJ](http://www.baeldung.com/aspectj)
|
- [Intro to AspectJ](http://www.baeldung.com/aspectj)
|
||||||
- [Spring Performance Logging](http://www.baeldung.com/spring-performance-logging)
|
- [Spring Performance Logging](http://www.baeldung.com/spring-performance-logging)
|
||||||
|
- [Introduction to Spring AOP](http://www.baeldung.com/spring-aop)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
## Relevant articles:
|
||||||
|
- [A Quick Guide to Using Keycloak with Spring Boot](http://www.baeldung.com/spring-boot-keycloak)
|
|
@ -28,4 +28,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
|
||||||
- [Spring Boot and Togglz Aspect](http://www.baeldung.com/spring-togglz)
|
- [Spring Boot and Togglz Aspect](http://www.baeldung.com/spring-togglz)
|
||||||
- [Getting Started with GraphQL and Spring Boot](http://www.baeldung.com/spring-graphql)
|
- [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)
|
- [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)
|
||||||
|
|
|
@ -3,4 +3,4 @@
|
||||||
## Spring Cloud CLI
|
## Spring Cloud CLI
|
||||||
|
|
||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
- [Introduction to Spring Cloud CLI](http://www.baeldung.com/introduction-to-spring-cloud-cli/)
|
- [Introduction to Spring Cloud CLI](http://www.baeldung.com/spring-cloud-cli)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue