Merge pull request #49 from eugenp/master

update
This commit is contained in:
Maiklins 2020-04-30 16:27:07 +02:00 committed by GitHub
commit 56f7b49988
101 changed files with 1797 additions and 751 deletions

View File

@ -1,4 +1,4 @@
package com.baeldung.java14.helpfulnullpointerexceptions;
package com.baeldung.java14.npe;
public class HelpfulNullPointerException {

View File

@ -5,5 +5,5 @@ This module contains articles about sorting arrays in Java
### Relevant Articles:
- [Sorting Arrays in Java](https://www.baeldung.com/java-sorting-arrays)
- [Checking If an Array Is Sorted in Java](https://www.baeldung.com/java-check-sorted-array)
- [How to Reverse an Array in Java](http://www.baeldung.com/java-invert-array)
- [How to Reverse an Array in Java](https://www.baeldung.com/java-invert-array)
- [Arrays.sort vs Arrays.parallelSort](https://www.baeldung.com/java-arrays-sort-vs-parallelsort)

View File

@ -4,4 +4,5 @@
### Relevant Articles:
- [Using a Mutex Object in Java](https://www.baeldung.com/java-mutex)
- [Testing Multi-Threaded Code in Java] (https://www.baeldung.com/java-testing-multithreaded)

View File

@ -15,6 +15,38 @@
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-java</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.googlecode.thread-weaver</groupId>
<artifactId>threadweaver</artifactId>
<version>0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.tempus-fugit</groupId>
<artifactId>tempus-fugit</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.googlecode.multithreadedtc</groupId>
<artifactId>multithreadedtc</artifactId>
<version>1.01</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jcstress</groupId>
<artifactId>jcstress-core</artifactId>
<version>0.5</version>
</dependency>
</dependencies>
<build>
<finalName>core-java-concurrency-2</finalName>
@ -24,6 +56,51 @@
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<compilerVersion>${javac.target}</compilerVersion>
<source>${javac.target}</source>
<target>${javac.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>main</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>jcstress</finalName>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.openjdk.jcstress.Main</mainClass>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/TestList</resource>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<javac.target>1.8</javac.target>
</properties>
</project>

View File

@ -1,5 +1,6 @@
package com.baeldung.concurrent;
import org.junit.Ignore;
import org.junit.Test;
import edu.umd.cs.mtc.MultithreadedTestCase;
@ -25,9 +26,10 @@ public class MyCounterMultithreadedTCUnitTest extends MultithreadedTestCase {
@SuppressWarnings("deprecation")
@Override
public void finish() {
assertEquals(2, counter.getCount());
assertEquals(2, counter.getCount());
}
@Ignore
@Test
public void testCounter() throws Throwable {
TestFramework.runManyTimes(new MyCounterMultithreadedTCUnitTest(), 1000);

View File

@ -6,6 +6,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Ignore;
import org.junit.Test;
public class MyCounterSimpleUnitTest {
@ -18,7 +19,8 @@ public class MyCounterSimpleUnitTest {
assertEquals(500, counter.getCount());
}
// @Test
@Ignore
@Test
public void testCounterWithConcurrency() throws InterruptedException {
int numberOfThreads = 100;
ExecutorService service = Executors.newFixedThreadPool(10);
@ -34,7 +36,8 @@ public class MyCounterSimpleUnitTest {
assertEquals(numberOfThreads, counter.getCount());
}
// @Test
@Ignore
@Test
public void testSummationWithConcurrencyAndWait() throws InterruptedException {
int numberOfThreads = 2;
ExecutorService service = Executors.newFixedThreadPool(10);

View File

@ -3,6 +3,7 @@ package com.baeldung.concurrent;
import static org.junit.Assert.assertEquals;
import org.junit.AfterClass;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
@ -20,6 +21,7 @@ public class MyCounterTempusFugitUnitTest {
private static MyCounter counter = new MyCounter();
@Ignore
@Test
@Concurrent(count = 2)
@Repeating(repetition = 10)

View File

@ -2,6 +2,7 @@ package com.baeldung.concurrent;
import static org.junit.Assert.assertEquals;
import org.junit.Ignore;
import org.junit.Test;
import com.google.testing.threadtester.AnnotatedTestRunner;
@ -34,6 +35,7 @@ public class MyCounterThreadWeaverUnitTest {
assertEquals(2, counter.getCount());
}
@Ignore
@Test
public void testCounter() {
new AnnotatedTestRunner().runTests(this.getClass(), MyCounter.class);

View File

@ -0,0 +1,60 @@
package com.baeldung.deadlockAndLivelock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class DeadlockExample {
private Lock lock1 = new ReentrantLock(true);
private Lock lock2 = new ReentrantLock(true);
public static void main(String[] args) {
DeadlockExample deadlock = new DeadlockExample();
new Thread(deadlock::operation1, "T1").start();
new Thread(deadlock::operation2, "T2").start();
}
public void operation1() {
lock1.lock();
print("lock1 acquired, waiting to acquire lock2.");
sleep(50);
lock2.lock();
print("lock2 acquired");
print("executing first operation.");
lock2.unlock();
lock1.unlock();
}
public void operation2() {
lock2.lock();
print("lock2 acquired, waiting to acquire lock1.");
sleep(50);
lock1.lock();
print("lock1 acquired");
print("executing second operation.");
lock1.unlock();
lock2.unlock();
}
public void print(String message) {
System.out.println("Thread " + Thread.currentThread()
.getName() + ": " + message);
}
public void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,86 @@
package com.baeldung.deadlockAndLivelock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LivelockExample {
private Lock lock1 = new ReentrantLock(true);
private Lock lock2 = new ReentrantLock(true);
public static void main(String[] args) {
LivelockExample livelock = new LivelockExample();
new Thread(livelock::operation1, "T1").start();
new Thread(livelock::operation2, "T2").start();
}
public void operation1() {
while (true) {
tryLock(lock1, 50);
print("lock1 acquired, trying to acquire lock2.");
sleep(50);
if (tryLock(lock2)) {
print("lock2 acquired.");
} else {
print("cannot acquire lock2, releasing lock1.");
lock1.unlock();
continue;
}
print("executing first operation.");
break;
}
lock2.unlock();
lock1.unlock();
}
public void operation2() {
while (true) {
tryLock(lock2, 50);
print("lock2 acquired, trying to acquire lock1.");
sleep(50);
if (tryLock(lock1)) {
print("lock1 acquired.");
} else {
print("cannot acquire lock1, releasing lock2.");
lock2.unlock();
continue;
}
print("executing second operation.");
break;
}
lock1.unlock();
lock2.unlock();
}
public void print(String message) {
System.out.println("Thread " + Thread.currentThread()
.getName() + ": " + message);
}
public void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void tryLock(Lock lock, long millis) {
try {
lock.tryLock(10, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public boolean tryLock(Lock lock) {
return lock.tryLock();
}
}

View File

@ -1,7 +0,0 @@
=========
## Core Java Concurrency Testing Examples
### Relevant Articles:
- [Testing Multi-Threaded Code in Java](https://www.baeldung.com/java-testing-multithreaded)

View File

@ -1,93 +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>core-java-concurrency-testing</artifactId>
<version>0.1.0-SNAPSHOT</version>
<name>core-java-concurrency-testing</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-java</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-java</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.googlecode.thread-weaver</groupId>
<artifactId>threadweaver</artifactId>
<version>0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.tempus-fugit</groupId>
<artifactId>tempus-fugit</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.googlecode.multithreadedtc</groupId>
<artifactId>multithreadedtc</artifactId>
<version>1.01</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jcstress</groupId>
<artifactId>jcstress-core</artifactId>
<version>0.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<compilerVersion>${javac.target}</compilerVersion>
<source>${javac.target}</source>
<target>${javac.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>main</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>jcstress</finalName>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.openjdk.jcstress.Main</mainClass>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/TestList</resource>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<logger name="org.springframework" level="WARN" />
<logger name="org.springframework.transaction" level="WARN" />
<!-- in order to debug some marshalling issues, this needs to be TRACE -->
<logger name="org.springframework.web.servlet.mvc" level="WARN" />
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -1,13 +0,0 @@
*.class
#folders#
/target
/neoDb*
/data
/src/main/webapp/WEB-INF/classes
*/META-INF/*
# Packaged files #
*.jar
*.war
*.ear

View File

@ -29,6 +29,11 @@
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons.lang3.version}</version>
</dependency>
<!-- test scoped -->
<dependency>
<groupId>org.assertj</groupId>
@ -40,6 +45,7 @@
<properties>
<javax.mail.version>1.5.0-b01</javax.mail.version>
<commons.lang3.version>3.10</commons.lang3.version>
<!-- testing -->
<assertj-core.version>3.10.0</assertj-core.version>
</properties>

View File

@ -0,0 +1,20 @@
package com.baeldung.exceptions.globalexceptionhandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Arithmetic {
private static Logger LOGGER = LoggerFactory.getLogger(Arithmetic.class);
public static void main(String[] args) {
try {
int result = 30 / 0; // Trying to divide by zero
} catch (ArithmeticException e) {
LOGGER.error("ArithmeticException caught!");
}
}
}

View File

@ -0,0 +1,24 @@
package com.baeldung.exceptions.globalexceptionhandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ArrayIndexOutOfBounds {
private static Logger LOGGER = LoggerFactory.getLogger(ArrayIndexOutOfBounds.class);
public static void main(String[] args) {
int[] nums = new int[] { 1, 2, 3 };
try {
int numFromNegativeIndex = nums[-1]; // Trying to access at negative index
int numFromGreaterIndex = nums[4]; // Trying to access at greater index
int numFromLengthIndex = nums[3]; // Trying to access at index equal to size of the array
} catch (ArrayIndexOutOfBoundsException e) {
LOGGER.error("ArrayIndexOutOfBoundsException caught");
}
}
}

View File

@ -0,0 +1,36 @@
package com.baeldung.exceptions.globalexceptionhandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class Animal {
}
class Dog extends Animal {
}
class Lion extends Animal {
}
public class ClassCast {
private static Logger LOGGER = LoggerFactory.getLogger(ClassCast.class);
public static void main(String[] args) {
try {
Animal animalOne = new Dog(); // At runtime the instance is dog
Dog bruno = (Dog) animalOne; // Downcasting
Animal animalTwo = new Lion(); // At runtime the instance is animal
Dog tommy = (Dog) animalTwo; // Downcasting
} catch (ClassCastException e) {
LOGGER.error("ClassCastException caught!");
}
}
}

View File

@ -0,0 +1,25 @@
package com.baeldung.exceptions.globalexceptionhandler;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FileNotFound {
private static Logger LOGGER = LoggerFactory.getLogger(FileNotFound.class);
public static void main(String[] args) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(new File("/invalid/file/location")));
} catch (FileNotFoundException e) {
LOGGER.error("FileNotFoundException caught!");
}
}
}

View File

@ -0,0 +1,28 @@
package com.baeldung.exceptions.globalexceptionhandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GlobalExceptionHandler {
public static void main(String[] args) {
Handler globalExceptionHandler = new Handler();
Thread.setDefaultUncaughtExceptionHandler(globalExceptionHandler);
new GlobalExceptionHandler().performArithmeticOperation(10, 0);
}
public int performArithmeticOperation(int num1, int num2) {
return num1/num2;
}
}
class Handler implements Thread.UncaughtExceptionHandler {
private static Logger LOGGER = LoggerFactory.getLogger(Handler.class);
public void uncaughtException(Thread t, Throwable e) {
LOGGER.info("Unhandled exception caught!");
}
}

View File

@ -0,0 +1,18 @@
package com.baeldung.exceptions.globalexceptionhandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class IllegalArgument {
private static Logger LOGGER = LoggerFactory.getLogger(IllegalArgument.class);
public static void main(String[] args) {
try {
Thread.sleep(-1000);
} catch (InterruptedException e) {
LOGGER.error("IllegalArgumentException caught!");
}
}
}

View File

@ -0,0 +1,32 @@
package com.baeldung.exceptions.globalexceptionhandler;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class IllegalState {
private static Logger LOGGER = LoggerFactory.getLogger(IllegalState.class);
public static void main(String[] args) {
List<Integer> intList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
intList.add(i);
}
Iterator<Integer> intListIterator = intList.iterator(); // Initialized with index at -1
try {
intListIterator.remove(); // IllegalStateException
} catch (IllegalStateException e) {
LOGGER.error("IllegalStateException caught!");
}
}
}

View File

@ -0,0 +1,28 @@
package com.baeldung.exceptions.globalexceptionhandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class ChildThread extends Thread {
private static Logger LOGGER = LoggerFactory.getLogger(ChildThread.class);
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
LOGGER.error("InterruptedException caught!");
}
}
}
public class InterruptedExceptionExample {
public static void main(String[] args) throws InterruptedException {
ChildThread childThread = new ChildThread();
childThread.start();
childThread.interrupt();
}
}

View File

@ -0,0 +1,25 @@
package com.baeldung.exceptions.globalexceptionhandler;
import java.net.MalformedURLException;
import java.net.URL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MalformedURL {
private static Logger LOGGER = LoggerFactory.getLogger(MalformedURL.class);
public static void main(String[] args) {
URL baeldungURL = null;
try {
baeldungURL = new URL("malformedurl");
} catch (MalformedURLException e) {
LOGGER.error("MalformedURLException caught!");
}
}
}

View File

@ -0,0 +1,36 @@
package com.baeldung.exceptions.globalexceptionhandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NullPointer {
private static Logger LOGGER = LoggerFactory.getLogger(NullPointer.class);
public static void main(String[] args) {
Person personObj = null;
try {
String name = personObj.personName; // Accessing the field of a null object
personObj.personName = "Jon Doe"; // Modifying the field of a null object
} catch (NullPointerException e) {
LOGGER.error("NullPointerException caught!");
}
}
}
class Person {
public String personName;
public String getPersonName() {
return personName;
}
public void setPersonName(String personName) {
this.personName = personName;
}
}

View File

@ -0,0 +1,23 @@
package com.baeldung.exceptions.globalexceptionhandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NumberFormat {
private static Logger LOGGER = LoggerFactory.getLogger(NumberFormat.class);
public static void main(String[] args) {
String str1 = "100ABCD";
try {
int x = Integer.parseInt(str1); // Converting string with inappropriate format
int y = Integer.valueOf(str1);
} catch (NumberFormatException e) {
LOGGER.error("NumberFormatException caught!");
}
}
}

View File

@ -0,0 +1,25 @@
package com.baeldung.exceptions.globalexceptionhandler;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ParseExceptionExample {
private static Logger LOGGER = LoggerFactory.getLogger(ParseExceptionExample.class);
public static void main(String[] args) {
DateFormat format = new SimpleDateFormat("MM, dd, yyyy");
try {
format.parse("01, , 2010");
} catch (ParseException e) {
LOGGER.error("ParseException caught!");
}
}
}

View File

@ -0,0 +1,23 @@
package com.baeldung.exceptions.globalexceptionhandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class StringIndexOutOfBounds {
private static Logger LOGGER = LoggerFactory.getLogger(StringIndexOutOfBounds.class);
public static void main(String[] args) {
String str = "Hello World";
try {
char charAtNegativeIndex = str.charAt(-1); // Trying to access at negative index
char charAtLengthIndex = str.charAt(11); // Trying to access at index equal to size of the string
} catch (StringIndexOutOfBoundsException e) {
LOGGER.error("StringIndexOutOfBoundsException caught");
}
}
}

View File

@ -0,0 +1,95 @@
package com.baeldung.exceptions.rootcausefinder;
import java.time.LocalDate;
import java.time.Period;
import java.time.format.DateTimeParseException;
import java.util.Objects;
/**
* Utility class to find root cause exceptions.
*/
public class RootCauseFinder {
public static Throwable findCauseUsingPlainJava(Throwable throwable) {
Objects.requireNonNull(throwable);
Throwable rootCause = throwable;
while (rootCause.getCause() != null) {
rootCause = rootCause.getCause();
}
return rootCause;
}
/**
* Calculates the age of a person from a given date.
*/
static class AgeCalculator {
private AgeCalculator() {
}
public static int calculateAge(String birthDate) throws CalculationException {
if (birthDate == null || birthDate.isEmpty()) {
throw new IllegalArgumentException();
}
try {
return Period
.between(parseDate(birthDate), LocalDate.now())
.getYears();
} catch (DateParseException ex) {
throw new CalculationException(ex);
}
}
private static LocalDate parseDate(String birthDateAsString) throws DateParseException {
LocalDate birthDate;
try {
birthDate = LocalDate.parse(birthDateAsString);
} catch (DateTimeParseException ex) {
throw new InvalidFormatException(birthDateAsString, ex);
}
if (birthDate.isAfter(LocalDate.now())) {
throw new DateOutOfRangeException(birthDateAsString);
}
return birthDate;
}
}
static class CalculationException extends Exception {
CalculationException(DateParseException ex) {
super(ex);
}
}
static class DateParseException extends Exception {
DateParseException(String input) {
super(input);
}
DateParseException(String input, Throwable thr) {
super(input, thr);
}
}
static class InvalidFormatException extends DateParseException {
InvalidFormatException(String input, Throwable thr) {
super("Invalid date format: " + input, thr);
}
}
static class DateOutOfRangeException extends DateParseException {
DateOutOfRangeException(String date) {
super("Date out of range: " + date);
}
}
}

View File

@ -0,0 +1,64 @@
package com.baeldung.exceptions.globalexceptionhandler;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.Appender;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verify;
@RunWith(MockitoJUnitRunner.class)
public class GlobalExceptionHandlerUnitTest {
@Mock
private Appender<ILoggingEvent> mockAppender;
@Captor
private ArgumentCaptor<LoggingEvent> captorLoggingEvent;
@Before
public void setup() {
final Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
logger.addAppender(mockAppender);
Handler globalExceptionHandler = new Handler();
Thread.setDefaultUncaughtExceptionHandler(globalExceptionHandler);
}
@After
public void teardown() {
final Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
logger.detachAppender(mockAppender);
}
@Test
public void whenArithmeticException_thenUseUncaughtExceptionHandler() throws InterruptedException {
Thread globalExceptionHandlerThread = new Thread() {
public void run() {
GlobalExceptionHandler globalExceptionHandlerObj = new GlobalExceptionHandler();
globalExceptionHandlerObj.performArithmeticOperation(99, 0);
}
};
globalExceptionHandlerThread.start();
globalExceptionHandlerThread.join();
verify(mockAppender).doAppend(captorLoggingEvent.capture());
LoggingEvent loggingEvent = captorLoggingEvent.getValue();
assertThat(loggingEvent.getLevel()).isEqualTo(Level.INFO);
assertThat(loggingEvent.getFormattedMessage()).isEqualTo("Unhandled exception caught!");
}
}

View File

@ -0,0 +1,99 @@
package com.baeldung.exceptions.rootcausefinder;
import com.baeldung.exceptions.rootcausefinder.RootCauseFinder.CalculationException;
import com.baeldung.exceptions.rootcausefinder.RootCauseFinder.DateOutOfRangeException;
import com.google.common.base.Throwables;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import static com.baeldung.exceptions.rootcausefinder.RootCauseFinder.AgeCalculator;
import static com.baeldung.exceptions.rootcausefinder.RootCauseFinder.findCauseUsingPlainJava;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Tests the {@link RootCauseFinder}.
*/
public class RootCauseFinderUnitTest {
@Test
public void givenBirthDate_whenCalculatingAge_thenAgeReturned() {
try {
int age = AgeCalculator.calculateAge("1990-01-01");
Assertions.assertEquals(1990, LocalDate
.now()
.minus(age, ChronoUnit.YEARS)
.getYear());
} catch (CalculationException e) {
Assertions.fail(e.getMessage());
}
}
@Test
public void givenWrongFormatDate_whenFindingRootCauseUsingJava_thenRootCauseFound() {
try {
AgeCalculator.calculateAge("010102");
} catch (CalculationException ex) {
assertTrue(findCauseUsingPlainJava(ex) instanceof DateTimeParseException);
}
}
@Test
public void givenOutOfRangeDate_whenFindingRootCauseUsingJava_thenRootCauseFound() {
try {
AgeCalculator.calculateAge("2020-04-04");
} catch (CalculationException ex) {
assertTrue(findCauseUsingPlainJava(ex) instanceof DateOutOfRangeException);
}
}
@Test
public void givenNullDate_whenFindingRootCauseUsingJava_thenRootCauseFound() {
try {
AgeCalculator.calculateAge(null);
} catch (Exception ex) {
assertTrue(findCauseUsingPlainJava(ex) instanceof IllegalArgumentException);
}
}
@Test
public void givenWrongFormatDate_whenFindingRootCauseUsingApacheCommons_thenRootCauseFound() {
try {
AgeCalculator.calculateAge("010102");
} catch (CalculationException ex) {
assertTrue(ExceptionUtils.getRootCause(ex) instanceof DateTimeParseException);
}
}
@Test
public void givenOutOfRangeDate_whenFindingRootCauseUsingApacheCommons_thenRootCauseFound() {
try {
AgeCalculator.calculateAge("2020-04-04");
} catch (CalculationException ex) {
assertTrue(ExceptionUtils.getRootCause(ex) instanceof DateOutOfRangeException);
}
}
@Test
public void givenWrongFormatDate_whenFindingRootCauseUsingGuava_thenRootCauseFound() {
try {
AgeCalculator.calculateAge("010102");
} catch (CalculationException ex) {
assertTrue(Throwables.getRootCause(ex) instanceof DateTimeParseException);
}
}
@Test
public void givenOutOfRangeDate_whenFindingRootCauseUsingGuava_thenRootCauseFound() {
try {
AgeCalculator.calculateAge("2020-04-04");
} catch (CalculationException ex) {
assertTrue(Throwables.getRootCause(ex) instanceof DateOutOfRangeException);
}
}
}

View File

@ -0,0 +1,95 @@
package com.baeldung.exceptions;
import java.time.LocalDate;
import java.time.Period;
import java.time.format.DateTimeParseException;
import java.util.Objects;
/**
* Utility class to find root cause exceptions.
*/
public class RootCauseFinder {
public static Throwable findCauseUsingPlainJava(Throwable throwable) {
Objects.requireNonNull(throwable);
Throwable rootCause = throwable;
while (rootCause.getCause() != null) {
rootCause = rootCause.getCause();
}
return rootCause;
}
/**
* Calculates the age of a person from a given date.
*/
static class AgeCalculator {
private AgeCalculator() {
}
public static int calculateAge(String birthDate) throws CalculationException {
if (birthDate == null || birthDate.isEmpty()) {
throw new IllegalArgumentException();
}
try {
return Period
.between(parseDate(birthDate), LocalDate.now())
.getYears();
} catch (DateParseException ex) {
throw new CalculationException(ex);
}
}
private static LocalDate parseDate(String birthDateAsString) throws DateParseException {
LocalDate birthDate;
try {
birthDate = LocalDate.parse(birthDateAsString);
} catch (DateTimeParseException ex) {
throw new InvalidFormatException(birthDateAsString, ex);
}
if (birthDate.isAfter(LocalDate.now())) {
throw new DateOutOfRangeException(birthDateAsString);
}
return birthDate;
}
}
static class CalculationException extends Exception {
CalculationException(DateParseException ex) {
super(ex);
}
}
static class DateParseException extends Exception {
DateParseException(String input) {
super(input);
}
DateParseException(String input, Throwable thr) {
super(input, thr);
}
}
static class InvalidFormatException extends DateParseException {
InvalidFormatException(String input, Throwable thr) {
super("Invalid date format: " + input, thr);
}
}
static class DateOutOfRangeException extends DateParseException {
DateOutOfRangeException(String date) {
super("Date out of range: " + date);
}
}
}

View File

@ -96,7 +96,7 @@
<!-- testing -->
<assertj.version>3.6.1</assertj.version>
<asspectj.version>1.8.9</asspectj.version>
<powermock.version>2.0.0-RC.4</powermock.version>
<powermock.version>2.0.0</powermock.version>
<jmockit.version>1.44</jmockit.version>
<!-- plugins -->
<maven-surefire-plugin.version>2.22.1</maven-surefire-plugin.version>

View File

@ -0,0 +1,59 @@
package com.baeldung.foldvsreduce
import org.junit.Test
import org.junit.jupiter.api.assertThrows
import java.lang.RuntimeException
import kotlin.test.assertEquals
class FoldAndReduceTest {
@Test
fun testReduceLimitations() {
val numbers: List<Int> = listOf(1, 2, 3)
val sum: Number = numbers.reduce { acc, next -> acc + next }
assertEquals(6, sum)
val emptyList = listOf<Int>()
assertThrows<RuntimeException> { emptyList.reduce { acc, next -> acc + next } }
// doesn't compile
// val sum = numbers.reduce { acc, next -> acc.toLong() + next.toLong()}
}
@Test
fun testFold() {
val numbers: List<Int> = listOf(1, 2, 3)
val sum: Int = numbers.fold(0, { acc, next -> acc + next })
assertEquals(6, sum)
//change result type
val sumLong: Long = numbers.fold(0L, { acc, next -> acc + next.toLong() })
assertEquals(6L, sumLong)
val emptyList = listOf<Int>()
val emptySum = emptyList.fold(0, { acc, next -> acc + next })
assertEquals(0, emptySum)
//power of changing result type
val (even, odd) = numbers.fold(Pair(listOf<Int>(), listOf<Int>()), { acc, next ->
if (next % 2 == 0) Pair(acc.first + next, acc.second)
else Pair(acc.first, acc.second + next)
})
assertEquals(listOf(2), even)
assertEquals(listOf(1, 3), odd)
}
@Test
fun testVariationsOfFold() {
val numbers = listOf(1, 2, 3)
val reversed = numbers.foldRight(listOf<Int>(), { next, acc -> acc + next})
assertEquals(listOf(3,2,1), reversed)
val reversedIndexes = numbers.foldRightIndexed(listOf<Int>(), { i, _, acc -> acc + i })
assertEquals(listOf(2,1,0), reversedIndexes)
}
}

View File

@ -256,10 +256,9 @@
</execution>
</executions>
<configuration>
<wsdlDirectory>src/main/resources</wsdlDirectory>
<wsdlFiles>
<wsdlFile>country.wsdl</wsdlFile>
</wsdlFiles>
<wsdlUrls>
<wsdlUrl>http://localhost:8888/ws/country?wsdl</wsdlUrl>
</wsdlUrls>
<keep>true</keep>
<packageName>com.baeldung.soap.ws.client.generated</packageName>
<sourceDestDir>src/main/java</sourceDestDir>

View File

@ -12,11 +12,11 @@ import javax.xml.ws.WebServiceFeature;
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.3.2
* JAX-WS RI 2.2.9-b130926.1035
* Generated source version: 2.2
*
*/
@WebServiceClient(name = "CountryServiceImplService", targetNamespace = "http://server.ws.soap.baeldung.com/", wsdlLocation = "file:src/main/resources/country.wsdl")
@WebServiceClient(name = "CountryServiceImplService", targetNamespace = "http://server.ws.soap.baeldung.com/", wsdlLocation = "http://localhost:8888/ws/country?wsdl")
public class CountryServiceImplService extends Service {
private final static URL COUNTRYSERVICEIMPLSERVICE_WSDL_LOCATION;
@ -27,7 +27,7 @@ public class CountryServiceImplService extends Service {
URL url = null;
WebServiceException e = null;
try {
url = new URL("file:src/main/resources/country.wsdl");
url = new URL("http://localhost:8888/ws/country?wsdl");
} catch (MalformedURLException ex) {
e = new WebServiceException(ex);
}

View File

@ -1,40 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><!-- Published by JAX-WS RI (http://jax-ws.java.net). RI's version is JAX-WS RI 2.2.9-b130926.1035 svn-revision#5f6196f2b90e9460065a4c2f4e30e065b245e51e. --><!-- Generated by JAX-WS RI (http://jax-ws.java.net). RI's version is JAX-WS RI 2.2.9-b130926.1035 svn-revision#5f6196f2b90e9460065a4c2f4e30e065b245e51e. -->
<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy"
xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://server.ws.soap.baeldung.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="http://server.ws.soap.baeldung.com/" name="CountryServiceImplService">
<types>
<xsd:schema>
<xsd:import namespace="http://server.ws.soap.baeldung.com/" schemaLocation="http://localhost:8888/ws/country?xsd=1"></xsd:import>
</xsd:schema>
</types>
<message name="findByName">
<part name="arg0" type="xsd:string"></part>
</message>
<message name="findByNameResponse">
<part name="return" type="tns:country"></part>
</message>
<portType name="CountryService">
<operation name="findByName">
<input wsam:Action="http://server.ws.soap.baeldung.com/CountryService/findByNameRequest" message="tns:findByName"></input>
<output wsam:Action="http://server.ws.soap.baeldung.com/CountryService/findByNameResponse" message="tns:findByNameResponse"></output>
</operation>
</portType>
<binding name="CountryServiceImplPortBinding" type="tns:CountryService">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"></soap:binding>
<operation name="findByName">
<soap:operation soapAction=""></soap:operation>
<input>
<soap:body use="literal" namespace="http://server.ws.soap.baeldung.com/"></soap:body>
</input>
<output>
<soap:body use="literal" namespace="http://server.ws.soap.baeldung.com/"></soap:body>
</output>
</operation>
</binding>
<service name="CountryServiceImplService">
<port name="CountryServiceImplPort" binding="tns:CountryServiceImplPortBinding">
<soap:address location="http://localhost:8888/ws/country"></soap:address>
</port>
</service>
</definitions>

View File

@ -1,20 +1,17 @@
package com.baeldung.batch.understanding;
import static org.junit.jupiter.api.Assertions.*;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Properties;
import javax.batch.operations.JobOperator;
import javax.batch.runtime.BatchRuntime;
import javax.batch.runtime.BatchStatus;
import javax.batch.runtime.JobExecution;
import javax.batch.runtime.Metric;
import javax.batch.runtime.StepExecution;
import com.baeldung.batch.understanding.BatchTestHelper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Disabled;
@Disabled("Should be fixed in BAEL-3812")
class CustomCheckPointUnitTest {
@Test
public void givenChunk_whenCustomCheckPoint_thenCommitCountIsThree() throws Exception {

View File

@ -1,6 +1,8 @@
package com.baeldung.batch.understanding;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.ArrayList;
import java.util.List;
@ -13,9 +15,7 @@ import javax.batch.runtime.JobExecution;
import javax.batch.runtime.StepExecution;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Disabled;
@Disabled("Should be fixed in BAEL-3812")
class JobSequenceUnitTest {
@Test
public void givenTwoSteps_thenBatch_CompleteWithSuccess() throws Exception {

View File

@ -1,17 +1,16 @@
package com.baeldung.batch.understanding;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Properties;
import javax.batch.operations.JobOperator;
import javax.batch.runtime.BatchRuntime;
import javax.batch.runtime.BatchStatus;
import javax.batch.runtime.JobExecution;
import java.util.Properties;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
@Disabled("Should be fixed in BAEL-3812")
class SimpleBatchLetUnitTest {
@Test
public void givenBatchLet_thenBatch_CompleteWithSuccess() throws Exception {

View File

@ -1,6 +1,7 @@
package com.baeldung.batch.understanding;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
import java.util.Map;
@ -14,9 +15,7 @@ import javax.batch.runtime.Metric;
import javax.batch.runtime.StepExecution;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Disabled;
@Disabled("Should be fixed in BAEL-3812")
class SimpleChunkUnitTest {
@Test
public void givenChunk_thenBatch_CompletesWithSucess() throws Exception {

View File

@ -1,19 +1,18 @@
package com.baeldung.batch.understanding;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.Assert.assertEquals;
import java.util.List;
import java.util.Properties;
import javax.batch.operations.JobOperator;
import javax.batch.runtime.BatchRuntime;
import javax.batch.runtime.BatchStatus;
import javax.batch.runtime.JobExecution;
import javax.batch.runtime.StepExecution;
import java.util.List;
import java.util.Properties;
import static org.junit.Assert.assertEquals;
import org.junit.jupiter.api.Test;
@Disabled("Should be fixed in BAEL-3812")
class SimpleErrorChunkUnitTest {
@Test

View File

@ -0,0 +1 @@
db-url=jdbc:h2:mem:jberet-repo;DB_CLOSE_DELAY=-1

View File

@ -1013,7 +1013,7 @@
<properties>
<lifecycle.mapping.version>1.0.0</lifecycle.mapping.version>
<spring.web.version>0.24.0-RC.0</spring.web.version>
<spring.web.version>0.24.0</spring.web.version>
<!-- Build properties -->
<maven.version>3.0.0</maven.version>
<java.version>1.8</java.version>

View File

@ -910,6 +910,6 @@
<sonar.tests>${project.basedir}/src/test/</sonar.tests>
<!-- jhipster-needle-maven-property -->
<zalando.version>0.24.0-RC.0</zalando.version>
<zalando.version>0.24.0</zalando.version>
</properties>
</project>

View File

@ -835,7 +835,7 @@
<properties>
<lifecycle.mapping.version>1.0.0</lifecycle.mapping.version>
<spring.web.version>0.24.0-RC.0</spring.web.version>
<spring.web.version>0.24.0</spring.web.version>
<!-- Build properties -->
<maven.version>3.0.0</maven.version>
<java.version>1.8</java.version>

View File

@ -1,6 +0,0 @@
## Maven and Java 11
This module contains articles about Maven with Java 11+.
### Relevant Articles:

View File

@ -1,17 +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.daomodule</groupId>
<artifactId>daomodule</artifactId>
<version>1.0</version>
<name>daomodule</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung.multimodule-maven-project</groupId>
<artifactId>multimodule-maven-project</artifactId>
<version>1.0</version>
</parent>
</project>

View File

@ -1,12 +0,0 @@
package com.baeldung.dao;
import java.util.List;
import java.util.Optional;
public interface Dao<T> {
Optional<T> findById(int id);
List<T> findAll();
}

View File

@ -1,3 +0,0 @@
module com.baeldung.dao {
exports com.baeldung.dao;
}

View File

@ -1,22 +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.entitymodule</groupId>
<artifactId>entitymodule</artifactId>
<version>1.0</version>
<name>entitymodule</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung.multimodule-maven-project</groupId>
<artifactId>multimodule-maven-project</artifactId>
<version>1.0</version>
</parent>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
</project>

View File

@ -1,19 +0,0 @@
package com.baeldung.entity;
public class User {
private final String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "User{" + "name=" + name + '}';
}
}

View File

@ -1,3 +0,0 @@
module com.baeldung.entity {
exports com.baeldung.entity;
}

View File

@ -1,38 +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.mainappmodule</groupId>
<artifactId>mainappmodule</artifactId>
<version>1.0</version>
<name>mainappmodule</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung.multimodule-maven-project</groupId>
<artifactId>multimodule-maven-project</artifactId>
<version>1.0</version>
<entitymodule.version>1.0</entitymodule.version>
<daomodule.version>1.0</daomodule.version>
<userdaomodule.version>1.0</userdaomodule.version>
</parent>
<dependencies>
<dependency>
<groupId>com.baeldung.entitymodule</groupId>
<artifactId>entitymodule</artifactId>
<version>${entitymodule.version}</version>
</dependency>
<dependency>
<groupId>com.baeldung.daomodule</groupId>
<artifactId>daomodule</artifactId>
<version>${daomodule.version}</version>
</dependency>
<dependency>
<groupId>com.baeldung.userdaomodule</groupId>
<artifactId>userdaomodule</artifactId>
<version>${userdaomodule.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -1,19 +0,0 @@
package com.baeldung.mainapp;
import com.baeldung.dao.Dao;
import com.baeldung.entity.User;
import com.baeldung.userdao.UserDao;
import java.util.HashMap;
import java.util.Map;
public class Application {
public static void main(String[] args) {
Map<Integer, User> users = new HashMap<>();
users.put(1, new User("Julie"));
users.put(2, new User("David"));
Dao userDao = new UserDao(users);
userDao.findAll().forEach(System.out::println);
}
}

View File

@ -1,6 +0,0 @@
module com.baeldung.mainapp {
requires com.baeldung.entity;
requires com.baeldung.userdao;
requires com.baeldung.dao;
uses com.baeldung.dao.Dao;
}

View File

@ -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.multimodule-maven-project</groupId>
<artifactId>multimodule-maven-project</artifactId>
<version>1.0</version>
<name>multimodule-maven-project</name>
<packaging>pom</packaging>
<parent>
<groupId>com.baeldung.maven-java-11</groupId>
<artifactId>maven-java-11</artifactId>
<version>1.0</version>
</parent>
<modules>
<module>entitymodule</module>
<module>daomodule</module>
<module>userdaomodule</module>
<module>mainappmodule</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler.plugin.version}</version>
<configuration>
<source>${source.version}</source>
<target>${target.version}</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>4.12</junit.version>
<assertj.version>3.12.2</assertj.version>
<compiler.plugin.version>3.8.0</compiler.plugin.version>
<source.version>11</source.version>
<target.version>11</target.version>
</properties>
</project>

View File

@ -1,42 +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.userdaomodule</groupId>
<artifactId>userdaomodule</artifactId>
<version>1.0</version>
<name>userdaomodule</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung.multimodule-maven-project</groupId>
<artifactId>multimodule-maven-project</artifactId>
<version>1.0</version>
</parent>
<dependencies>
<dependency>
<groupId>com.baeldung.entitymodule</groupId>
<artifactId>entitymodule</artifactId>
<version>${entitymodule.version}1.0</version>
</dependency>
<dependency>
<groupId>com.baeldung.daomodule</groupId>
<artifactId>daomodule</artifactId>
<version>${daomodule.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<entitymodule.version>1.0</entitymodule.version>
<daomodule.version>1.0</daomodule.version>
</properties>
</project>

View File

@ -1,32 +0,0 @@
package com.baeldung.userdao;
import com.baeldung.dao.Dao;
import com.baeldung.entity.User;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class UserDao implements Dao<User> {
private final Map<Integer, User> users;
public UserDao() {
users = new HashMap<>();
}
public UserDao(Map<Integer, User> users) {
this.users = users;
}
@Override
public List<User> findAll() {
return new ArrayList<>(users.values());
}
@Override
public Optional<User> findById(int id) {
return Optional.ofNullable(users.get(id));
}
}

View File

@ -1,6 +0,0 @@
module com.baeldung.userdao {
requires com.baeldung.entity;
requires com.baeldung.dao;
provides com.baeldung.dao.Dao with com.baeldung.userdao.UserDao;
exports com.baeldung.userdao;
}

View File

@ -1,36 +0,0 @@
package com.baeldung.userdao.test;
import com.baeldung.dao.Dao;
import com.baeldung.entity.User;
import com.baeldung.userdao.UserDao;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.junit.Before;
import org.junit.Test;
public class UserDaoUnitTest {
private Dao userDao;
@Before
public void setUpUserDaoInstance() {
Map<Integer, User> users = new HashMap<>();
users.put(1, new User("Julie"));
users.put(2, new User("David"));
userDao = new UserDao(users);
}
@Test
public void givenUserDaoIntance_whenCalledFindById_thenCorrect() {
assertThat(userDao.findById(1), isA(Optional.class));
}
@Test
public void givenUserDaoIntance_whenCalledFindAll_thenCorrect() {
assertThat(userDao.findAll(), isA(List.class));
}
}

View File

@ -1,27 +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.maven-java-11</groupId>
<artifactId>maven-java-11</artifactId>
<version>1.0</version>
<name>maven-java-11</name>
<packaging>pom</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modules>
<module>multimodule-maven-project</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
</project>

View File

@ -14,8 +14,8 @@ public interface AddressMapper {
@Results(value = { @Result(property = "addressId", column = "addressId"),
@Result(property = "streetAddress", column = "streetAddress"),
@Result(property = "person", column = "personId", javaType = Person.class, one = @One(select = "getPerson")) })
Address getAddresses(Integer addressID);
Address getAddresses(Integer addressId);
@Select("SELECT personId FROM address WHERE addressId = #{addressId})")
Person getPerson(Integer personId);
Person getPerson(Integer addressId);
}

View File

@ -0,0 +1,35 @@
package com.baeldung.s;
public class TextManipulator {
private String text;
public TextManipulator(String text) {
this.text = text;
}
public String getText() {
return text;
}
public void appendText(String newText) {
text = text.concat(newText);
}
public void findWordAndReplace(String word, String replacementWord) {
if (text.contains(word)) {
text = text.replace(word, replacementWord);
} else System.out.println("Word you want to replace is not found in the text");
}
public void findWordAndDelete(String word) {
if (text.contains(word)) {
text = text.replace(word, "");
} else System.out.println("Word you want to delete is not found in the text");
}
/*
* Bad practice when implementing SRP principle, not in the scope of this class
public void printText() {
System.out.println(textManipulator.getText());
}*/
}

View File

@ -0,0 +1,23 @@
package com.baeldung.s;
import java.util.Arrays;
public class TextPrinter {
TextManipulator textManipulator;
public TextPrinter(TextManipulator textManipulator) {
this.textManipulator = textManipulator;
}
public void printText() {
System.out.println(textManipulator.getText());
}
public void printOutEachWordOfText() {
System.out.println(Arrays.toString(textManipulator.getText().split(" ")));
}
public void printRangeOfCharacters(int startingIndex, int endIndex) {
System.out.println(textManipulator.getText().substring(startingIndex, endIndex));
}
}

View File

@ -48,6 +48,17 @@
<version>${postgres.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>${querydsl.version}</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
@ -101,23 +112,41 @@
<configuration>
<sources>
<source>target/metamodel</source>
<source>${project.build.directory}/generated-sources/java/</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<hibernate.version>5.4.0.Final</hibernate.version>
<eclipselink.version>2.7.4-RC1</eclipselink.version>
<hibernate.version>5.4.14.Final</hibernate.version>
<eclipselink.version>2.7.4</eclipselink.version>
<postgres.version>42.2.5</postgres.version>
<javax.persistence-api.version>2.2</javax.persistence-api.version>
<assertj.version>3.11.1</assertj.version>
<maven-compiler-plugin.version>3.5.1</maven-compiler-plugin.version>
<maven-processor-plugin.version>3.3.3</maven-processor-plugin.version>
<build-helper-maven-plugin.version>3.0.0</build-helper-maven-plugin.version>
<querydsl.version>4.3.1</querydsl.version>
</properties>
</project>
</project>

View File

@ -0,0 +1,90 @@
package com.baeldung.jpa.unrelated.entities;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import javax.persistence.*;
import java.util.List;
import java.util.Objects;
@Entity
@Table(name = "menu")
public class Cocktail {
@Id
@Column(name = "cocktail_name")
private String name;
@Column
private double price;
@Column(name = "category")
private String category;
@OneToOne
@NotFound(action = NotFoundAction.IGNORE)
@JoinColumn(name = "cocktail_name",
referencedColumnName = "cocktail",
insertable = false, updatable = false,
foreignKey = @javax.persistence
.ForeignKey(value = ConstraintMode.NO_CONSTRAINT))
private Recipe recipe;
@OneToMany(fetch = FetchType.LAZY)
@NotFound(action = NotFoundAction.IGNORE)
@JoinColumn(
name = "cocktail",
referencedColumnName = "cocktail_name",
insertable = false,
updatable = false,
foreignKey = @javax.persistence
.ForeignKey(value = ConstraintMode.NO_CONSTRAINT))
private List<MultipleRecipe> recipeList;
public Cocktail() {
}
public Cocktail(String name, double price, String baseIngredient) {
this.name = name;
this.price = price;
this.category = baseIngredient;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
public String getCategory() {
return category;
}
public Recipe getRecipe() {
return recipe;
}
public List<MultipleRecipe> getRecipeList() {
return recipeList;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Cocktail cocktail = (Cocktail) o;
return Double.compare(cocktail.price, price) == 0 &&
Objects.equals(name, cocktail.name) &&
Objects.equals(category, cocktail.category);
}
@Override
public int hashCode() {
return Objects.hash(name, price, category);
}
}

View File

@ -0,0 +1,71 @@
package com.baeldung.jpa.unrelated.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Objects;
@Entity
@Table(name = "multiple_recipes")
public class MultipleRecipe {
@Id
@Column(name = "id")
private Long id;
@Column(name = "cocktail")
private String cocktail;
@Column(name = "instructions")
private String instructions;
@Column(name = "base_ingredient")
private String baseIngredient;
public MultipleRecipe() {
}
public MultipleRecipe(Long id, String cocktail,
String instructions, String baseIngredient) {
this.id = id;
this.cocktail = cocktail;
this.instructions = instructions;
this.baseIngredient = baseIngredient;
}
public Long getId() {
return id;
}
public String getCocktail() {
return cocktail;
}
public String getInstructions() {
return instructions;
}
public String getBaseIngredient() {
return baseIngredient;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
MultipleRecipe that = (MultipleRecipe) o;
return Objects.equals(id, that.id) &&
Objects.equals(cocktail, that.cocktail) &&
Objects.equals(instructions, that.instructions) &&
Objects.equals(baseIngredient, that.baseIngredient);
}
@Override
public int hashCode() {
return Objects.hash(id, cocktail,
instructions, baseIngredient);
}
}

View File

@ -0,0 +1,50 @@
package com.baeldung.jpa.unrelated.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Objects;
@Entity
@Table(name="recipes")
public class Recipe {
@Id
@Column(name = "cocktail")
private String cocktail;
@Column
private String instructions;
public Recipe() {
}
public Recipe(String cocktail, String instructions) {
this.cocktail = cocktail;
this.instructions = instructions;
}
public String getCocktail() {
return cocktail;
}
public String getInstructions() {
return instructions;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Recipe recipe = (Recipe) o;
return Objects.equals(cocktail, recipe.cocktail)
&& Objects.equals(instructions, recipe.instructions);
}
@Override
public int hashCode() {
return Objects.hash(cocktail, instructions);
}
}

View File

@ -162,5 +162,26 @@
value="false" />
</properties>
</persistence-unit>
</persistence>
<persistence-unit name="jpa-h2-unrelated-entities">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.baeldung.jpa.unrelated.entities.Cocktail</class>
<class>com.baeldung.jpa.unrelated.entities.Recipe</class>
<class>com.baeldung.jpa.unrelated.entities.MultipleRecipe</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.driver"
value="org.h2.Driver" />
<property name="javax.persistence.jdbc.url"
value="jdbc:h2:mem:test" />
<property name="javax.persistence.jdbc.user" value="sa" />
<property name="javax.persistence.jdbc.password" value="" />
<property name="hibernate.dialect"
value="org.hibernate.dialect.H2Dialect" />
<property name="hibernate.hbm2ddl.auto" value="create" />
<property name="show_sql" value="true" />
<property name="hibernate.temp.use_jdbc_metadata_defaults"
value="false" />
</properties>
</persistence-unit>
</persistence>

View File

@ -0,0 +1,189 @@
package com.baeldung.jpa.unrelated.entities;
import javax.persistence.*;
import com.querydsl.jpa.impl.JPAQuery;
import org.junit.jupiter.api.*;
import java.util.List;
import java.util.function.Consumer;
import static org.junit.jupiter.api.Assertions.*;
public class UnrelatedEntitiesUnitTest {
private static EntityManagerFactory entityManagerFactory;
private static EntityManager entityManager;
private static Cocktail mojito;
private static Cocktail ginTonic;
@BeforeAll
public static void setup() {
entityManagerFactory = Persistence.createEntityManagerFactory("jpa-h2-unrelated-entities");
entityManager = entityManagerFactory.createEntityManager();
mojito = new Cocktail("Mojito", 11, "Rum");
ginTonic = new Cocktail("Gin tonic", 8.50, "Gin");
entityManager.getTransaction().begin();
entityManager.persist(mojito);
entityManager.persist(ginTonic);
entityManager.persist(new Recipe(mojito.getName(), "Some instructions"));
entityManager.persist(new MultipleRecipe(1L, mojito.getName(),
"some instructions", mojito.getCategory()));
entityManager.persist(new MultipleRecipe(2L, mojito.getName(),
"some other instructions", mojito.getCategory()));
entityManager.getTransaction().commit();
}
@AfterAll
public static void closeSession() {
entityManager.close();
}
@Test
public void givenCocktailsWithRecipe_whenQuerying_thenTheExpectedCocktailsReturned() {
// JPA
Cocktail cocktail = entityManager.createQuery("select c "
+ "from Cocktail c join c.recipe", Cocktail.class)
.getSingleResult();
verifyResult(mojito, cocktail);
cocktail = entityManager.createQuery("select c "
+ "from Cocktail c join Recipe r "
+ "on c.name = r.cocktail", Cocktail.class)
.getSingleResult();
verifyResult(mojito, cocktail);
// QueryDSL
cocktail = new JPAQuery<Cocktail>(entityManager).from(QCocktail.cocktail)
.join(QCocktail.cocktail.recipe)
.fetchOne();
verifyResult(mojito, cocktail);
cocktail = new JPAQuery<Cocktail>(entityManager).from(QCocktail.cocktail)
.join(QRecipe.recipe)
.on(QCocktail.cocktail.name.eq(QRecipe.recipe.cocktail))
.fetchOne();
verifyResult(mojito, cocktail);
}
@Test
public void givenCocktailsWithoutRecipe_whenQuerying_thenTheExpectedCocktailsReturned() {
Cocktail cocktail = entityManager.createQuery("select c "
+ "from Cocktail c left join c.recipe r "
+ "where r is null", Cocktail.class)
.getSingleResult();
verifyResult(ginTonic, cocktail);
cocktail = entityManager.createQuery("select c "
+ "from Cocktail c left join Recipe r "
+ "on c.name = r.cocktail "
+ "where r is null", Cocktail.class)
.getSingleResult();
verifyResult(ginTonic, cocktail);
QRecipe recipe = new QRecipe("alias");
cocktail = new JPAQuery<Cocktail>(entityManager).from(QCocktail.cocktail)
.leftJoin(QCocktail.cocktail.recipe, recipe)
.where(recipe.isNull())
.fetchOne();
verifyResult(ginTonic, cocktail);
cocktail = new JPAQuery<Cocktail>(entityManager).from(QCocktail.cocktail)
.leftJoin(QRecipe.recipe)
.on(QCocktail.cocktail.name.eq(QRecipe.recipe.cocktail))
.where(QRecipe.recipe.isNull())
.fetchOne();
verifyResult(ginTonic, cocktail);
}
@Test
public void givenCocktailsWithMultipleRecipes_whenQuerying_thenTheExpectedCocktailsReturned() {
// JPQL
Cocktail cocktail = entityManager.createQuery("select c "
+ "from Cocktail c join c.recipeList", Cocktail.class)
.getSingleResult();
verifyResult(mojito, cocktail);
cocktail = entityManager.createQuery("select c "
+ "from Cocktail c join MultipleRecipe mr "
+ "on mr.cocktail = c.name", Cocktail.class)
.getSingleResult();
verifyResult(mojito, cocktail);
// QueryDSL
cocktail = new JPAQuery<Cocktail>(entityManager).from(QCocktail.cocktail)
.join(QCocktail.cocktail.recipeList)
.fetchOne();
verifyResult(mojito, cocktail);
cocktail = new JPAQuery<Cocktail>(entityManager).from(QCocktail.cocktail)
.join(QMultipleRecipe.multipleRecipe)
.on(QCocktail.cocktail.name.eq(QMultipleRecipe.multipleRecipe.cocktail))
.fetchOne();
verifyResult(mojito, cocktail);
}
@Test
public void givenCocktailsWithoutMultipleRecipes_whenQuerying_thenTheExpectedCocktailsReturned() {
// JPQL
Cocktail cocktail = entityManager.createQuery("select c "
+ "from Cocktail c left join c.recipeList r "
+ "where r is null", Cocktail.class)
.getSingleResult();
verifyResult(ginTonic, cocktail);
cocktail = entityManager.createQuery("select c "
+ "from Cocktail c left join MultipleRecipe r "
+ "on c.name = r.cocktail "
+ "where r is null", Cocktail.class)
.getSingleResult();
verifyResult(ginTonic, cocktail);
// QueryDSL
QMultipleRecipe multipleRecipe = new QMultipleRecipe("alias");
cocktail = new JPAQuery<Cocktail>(entityManager).from(QCocktail.cocktail)
.leftJoin(QCocktail.cocktail.recipeList, multipleRecipe)
.where(multipleRecipe.isNull())
.fetchOne();
verifyResult(ginTonic, cocktail);
cocktail = new JPAQuery<Cocktail>(entityManager).from(QCocktail.cocktail)
.leftJoin(QMultipleRecipe.multipleRecipe)
.on(QCocktail.cocktail.name.eq(QMultipleRecipe.multipleRecipe.cocktail))
.where(QMultipleRecipe.multipleRecipe.isNull())
.fetchOne();
verifyResult(ginTonic, cocktail);
}
@Test
public void givenMultipleRecipesWithCocktails_whenQuerying_thenTheExpectedMultipleRecipesReturned() {
Consumer<List<MultipleRecipe>> verifyResult = recipes -> {
assertEquals(2, recipes.size());
recipes.forEach(r -> assertEquals(mojito.getName(), r.getCocktail()));
};
// JPQL
List<MultipleRecipe> recipes = entityManager.createQuery("select distinct r "
+ "from MultipleRecipe r "
+ "join Cocktail c "
+ "on r.baseIngredient = c.category",
MultipleRecipe.class).getResultList();
verifyResult.accept(recipes);
// QueryDSL
QCocktail cocktail = QCocktail.cocktail;
QMultipleRecipe multipleRecipe = QMultipleRecipe.multipleRecipe;
recipes = new JPAQuery<MultipleRecipe>(entityManager).from(multipleRecipe)
.join(cocktail)
.on(multipleRecipe.baseIngredient.eq(cocktail.category))
.fetch();
verifyResult.accept(recipes);
}
private void verifyResult(Cocktail expectedCocktail, Cocktail queryResult) {
assertNotNull(queryResult);
assertEquals(expectedCocktail, queryResult);
}
}

View File

@ -106,7 +106,7 @@
<properties>
<hibernate.version>5.4.0.Final</hibernate.version>
<eclipselink.version>2.7.4-RC1</eclipselink.version>
<eclipselink.version>2.7.4</eclipselink.version>
<postgres.version>42.2.5</postgres.version>
<javax.persistence-api.version>2.2</javax.persistence-api.version>
<maven-processor-plugin.version>3.3.3</maven-processor-plugin.version>

View File

@ -13,3 +13,12 @@
- [Spring Data Annotations](http://www.baeldung.com/spring-data-annotations)
- [Spring Data MongoDB Transactions](https://www.baeldung.com/spring-data-mongodb-transactions )
- [ZonedDateTime with Spring Data MongoDB](https://www.baeldung.com/spring-data-mongodb-zoneddatetime)
## Spring Data MongoDB Live Testing
There are 3 scripts to simplify running live tests:
1. [`live-test-setup.sh`](src/live-test/resources/live-test-setup.sh) builds a docker image with the necessary setup and runs it. The environment is ready, when the log stops - it takes approximately 30 seconds.
2. [`live-test.sh`](src/live-test/resources/live-test.sh) runs the live tests (but no other tests).
3. [`live-test-teardown.sh`](src/live-test/resources/live-test-teardown.sh) stops and removes the docker image.

View File

@ -0,0 +1,8 @@
FROM mongo:4.2.1
COPY init-session.js /docker-entrypoint-initdb.d/
EXPOSE 27017
HEALTHCHECK --interval=5s --timeout=3s --start-period=10s CMD mongo db.stats()
CMD ["mongod", "--replSet", "rs0"]

View File

@ -0,0 +1 @@
rs.initiate();

View File

@ -0,0 +1,5 @@
#!/bin/bash
docker image build -t spring-data-mongodb:live-test .
docker run -p 27017:27017 --name spring-data-mongodb-live-test spring-data-mongodb:live-test

View File

@ -0,0 +1,4 @@
#!/bin/bash
docker stop spring-data-mongodb-live-test
docker rm spring-data-mongodb-live-test

View File

@ -0,0 +1,3 @@
#!/bin/bash
mvn clean compile test -P live-all -f ../../../pom.xml

View File

@ -62,24 +62,6 @@ public class MongoTransactionalLiveTest {
}
}
@Test(expected = MongoCommandException.class)
@Transactional
public void whenCountDuringMongoTransaction_thenException() {
userRepository.save(new User("John", 30));
userRepository.save(new User("Ringo", 35));
userRepository.count();
}
@Test
@Transactional
public void whenQueryDuringMongoTransaction_thenSuccess() {
userRepository.save(new User("Jane", 20));
userRepository.save(new User("Nick", 33));
List<User> users = mongoTemplate.find(new Query(), User.class);
assertTrue(users.size() > 1);
}
// ==== Using test instead of before and after due to @transactional doesn't allow list collection
@Test

32
pom.xml
View File

@ -814,6 +814,7 @@
<module>vaadin</module>
<module>vavr</module>
<module>vavr-2</module>
</modules>
</profile>
@ -1313,10 +1314,41 @@
<module>vaadin</module>
<module>vavr</module>
<module>vavr-2</module>
</modules>
</profile>
<profile>
<id>live-all</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/SpringContextTest.java</exclude>
<exclude>**/*UnitTest.java</exclude>
<exclude>**/*IntegrationTest.java</exclude>
<exclude>**/*IntTest.java</exclude>
<exclude>**/*LongRunningUnitTest.java</exclude>
<exclude>**/*ManualTest.java</exclude>
<exclude>**/*JdbcTest.java</exclude>
</excludes>
<includes>
<include>**/*LiveTest.java</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<reporting>

View File

@ -1,32 +0,0 @@
package com.baeldung.manuallogout;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Controller
public class BasicAuthController {
@RequestMapping(value = {"/basiclogout"}, method = RequestMethod.POST)
public String logout(HttpServletRequest request, HttpServletResponse response) {
HttpSession session;
SecurityContextHolder.clearContext();
session = request.getSession(false);
if (session != null) {
session.invalidate();
}
for (Cookie cookie : request.getCookies()) {
String cookieName = cookie.getName();
Cookie cookieToDelete = new Cookie(cookieName, null);
cookieToDelete.setMaxAge(0);
response.addCookie(cookieToDelete);
}
return "redirect:/login?logout";
}
}

View File

@ -1,29 +0,0 @@
package com.baeldung.manuallogout;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.HeaderWriterLogoutHandler;
import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter;
import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Controller
public class ClearSiteDataController {
Directive[] SOURCE = {Directive.COOKIES, Directive.STORAGE, Directive.EXECUTION_CONTEXTS, Directive.CACHE};
@RequestMapping(value = {"/csdlogout"}, method = RequestMethod.POST)
public String logout(HttpServletRequest request, HttpServletResponse response) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) {
ClearSiteDataHeaderWriter csdHeaderWriter = new ClearSiteDataHeaderWriter(SOURCE);
new HeaderWriterLogoutHandler(csdHeaderWriter).logout(request, response, auth);
}
return "redirect:/login?logout";
}
}

View File

@ -1,39 +1,80 @@
package com.baeldung.manuallogout;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler;
import org.springframework.security.web.authentication.logout.HeaderWriterLogoutHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter;
import javax.servlet.http.Cookie;
import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.*;
@Configuration
@EnableWebSecurity
public class SimpleSecurityConfiguration extends WebSecurityConfigurerAdapter {
public class SimpleSecurityConfiguration {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginProcessingUrl("/login")
.loginPage("/login")
.usernameParameter("username")
.passwordParameter("password")
.defaultSuccessUrl("/")
.failureUrl("/login?error");
@Order(3)
@Configuration
public static class DefaultLogoutConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/basic/**")
.authorizeRequests(authz -> authz.anyRequest().permitAll())
.logout(logout -> logout
.logoutUrl("/basic/basiclogout")
.addLogoutHandler(new SecurityContextLogoutHandler())
.addLogoutHandler(new CookieClearingLogoutHandler(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY))
);
}
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user")
.password("password")
.roles("USER")
.and()
.withUser("manager")
.password("password")
.credentialsExpired(true)
.accountExpired(true)
.accountLocked(true)
.authorities("WRITE_PRIVILEGES", "READ_PRIVILEGES")
.roles("MANAGER");
@Order(2)
@Configuration
public static class AllCookieClearingLogoutConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/cookies/**")
.authorizeRequests(authz -> authz.anyRequest().permitAll())
.logout(logout -> logout
.logoutUrl("/cookies/cookielogout")
.addLogoutHandler(new SecurityContextLogoutHandler())
.addLogoutHandler((request, response, auth) -> {
for (Cookie cookie : request.getCookies()) {
String cookieName = cookie.getName();
Cookie cookieToDelete = new Cookie(cookieName, null);
cookieToDelete.setMaxAge(0);
response.addCookie(cookieToDelete);
}
}
));
}
}
@Order(1)
@Configuration
public static class ClearSiteDataHeaderLogoutConfiguration extends WebSecurityConfigurerAdapter {
private static final ClearSiteDataHeaderWriter.Directive[] SOURCE =
{ CACHE, COOKIES, STORAGE, EXECUTION_CONTEXTS };
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/csd/**")
.authorizeRequests(authz -> authz.anyRequest().permitAll())
.logout(logout -> logout
.logoutUrl("/csd/csdlogout")
.addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(SOURCE)))
);
}
}
}

View File

@ -7,6 +7,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
@ -36,7 +37,22 @@ public class ManualLogoutIntegrationTest {
@WithMockUser(value = "spring")
@Test
public void givenLoggedUserWhenUserLogoutThenSessionCleared() throws Exception {
public void givenLoggedUserWhenUserLogoutThenSessionClearedAndNecessaryCookieCleared() throws Exception {
MockHttpServletRequest requestStateAfterLogout = this.mockMvc.perform(post("/basic/basiclogout").secure(true).with(csrf()))
.andExpect(status().is3xxRedirection())
.andExpect(unauthenticated())
.andExpect(cookie().maxAge(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, 0))
.andReturn()
.getRequest();
HttpSession sessionStateAfterLogout = requestStateAfterLogout.getSession();
assertNull(sessionStateAfterLogout.getAttribute(ATTRIBUTE_NAME));
}
@WithMockUser(value = "spring")
@Test
public void givenLoggedUserWhenUserLogoutThenSessionClearedAndAllCookiesCleared() throws Exception {
MockHttpSession session = new MockHttpSession();
session.setAttribute(ATTRIBUTE_NAME, ATTRIBUTE_VALUE);
@ -44,7 +60,7 @@ public class ManualLogoutIntegrationTest {
Cookie randomCookie = new Cookie(COOKIE_NAME, COOKIE_VALUE);
randomCookie.setMaxAge(EXPIRY); // 10 minutes
MockHttpServletRequest requestStateAfterLogout = this.mockMvc.perform(post("/basiclogout").secure(true).with(csrf()).session(session).cookie(randomCookie))
MockHttpServletRequest requestStateAfterLogout = this.mockMvc.perform(post("/cookies/cookielogout").secure(true).with(csrf()).session(session).cookie(randomCookie))
.andExpect(status().is3xxRedirection())
.andExpect(unauthenticated())
.andExpect(cookie().maxAge(COOKIE_NAME, 0))
@ -53,15 +69,13 @@ public class ManualLogoutIntegrationTest {
HttpSession sessionStateAfterLogout = requestStateAfterLogout.getSession();
assertNull(sessionStateAfterLogout.getAttribute(ATTRIBUTE_NAME));
}
@WithMockUser(value = "spring")
@Test
public void givenLoggedUserWhenUserLogoutThenClearDataSiteHeaderPresent() throws Exception {
this.mockMvc.perform(post("/csdlogout").secure(true).with(csrf()))
this.mockMvc.perform(post("/csd/csdlogout").secure(true).with(csrf()))
.andDo(print())
.andExpect(status().is3xxRedirection())
.andExpect(header().exists(CLEAR_SITE_DATA_HEADER))

View File

@ -63,7 +63,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-boot.version>1.5.2.RELEASE</spring-boot.version>
<spring-boot.version>2.2.6.RELEASE</spring-boot.version>
<greeter.version>0.0.1-SNAPSHOT</greeter.version>
</properties>

View File

@ -51,7 +51,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<greeter.version>0.0.1-SNAPSHOT</greeter.version>
<spring-boot.version>1.5.2.RELEASE</spring-boot.version>
<spring-boot.version>2.2.6.RELEASE</spring-boot.version>
</properties>
</project>

View File

@ -24,6 +24,12 @@
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
@ -72,7 +78,7 @@
</build>
<properties>
<spring-boot.version>1.5.10.RELEASE</spring-boot.version>
<spring-boot.version>2.2.6.RELEASE</spring-boot.version>
<custom.property>Custom Property Value</custom.property>
<apache-maven.version>2.7</apache-maven.version>
<exec-maven-plugin.version>1.6.0</exec-maven-plugin.version>

View File

@ -9,9 +9,9 @@
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-1</artifactId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../../parent-boot-1</relativePath>
<relativePath>../../../parent-boot-2</relativePath>
</parent>
<dependencies>

View File

@ -2,66 +2,64 @@
<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-caching</artifactId>
<version>0.1-SNAPSHOT</version>
<name>spring-caching</name>
<packaging>war</packaging>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-caching</artifactId>
<version>0.1-SNAPSHOT</version>
<name>spring-caching</name>
<packaging>war</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-boot-2</relativePath>
</parent>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-boot-2</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
</dependencies>
<properties>
<ehcache.version>3.5.2</ehcache.version>
</properties>
</project>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
</dependencies>
<properties>
<ehcache.version>3.5.2</ehcache.version>
</properties>
</project>

View File

@ -72,7 +72,7 @@ node {
if (isUnix()) {
sh 'nohup ./mvnw spring-boot:run -Dserver.port=8989 &'
} else {
bat 'start ./mvnw.cmd spring-boot:run -Dserver.port=8989'
bat 'start mvnw.cmd spring-boot:run -Dserver.port=8989'
}
}
}

8
vavr-2/README.md Normal file
View File

@ -0,0 +1,8 @@
## Vavr
This module contains articles about Vavr.
### Relevant Articles:
- [Introduction to Vavrs Either](https://www.baeldung.com/vavr-either)
- [Interoperability Between Java and Vavr](https://www.baeldung.com/java-vavr)
- [[<-- prev]](/vavr)

27
vavr-2/pom.xml Normal file
View File

@ -0,0 +1,27 @@
<?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">
<parent>
<artifactId>parent-modules</artifactId>
<groupId>com.baeldung</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>vavr-2</artifactId>
<name>vavr-2</name>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr-test</artifactId>
<version>${vavr.version}</version>
</dependency>
</dependencies>
<properties>
<vavr.version>0.9.1</vavr.version>
</properties>
</project>

Some files were not shown because too many files have changed in this diff Show More