BAEL-6865, Aggregate Runtime Exceptions in Java Streams
Changed method names
This commit is contained in:
parent
4aba635055
commit
9b1d47ff4e
|
@ -38,6 +38,11 @@
|
|||
<version>3.12.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.vavr</groupId>
|
||||
<artifactId>vavr</artifactId>
|
||||
<version>${vavr.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -67,6 +72,7 @@
|
|||
<maven-compiler-plugin.version>3.1</maven-compiler-plugin.version>
|
||||
<maven.compiler.source>12</maven.compiler.source>
|
||||
<maven.compiler.target>12</maven.compiler.target>
|
||||
<vavr.version>0.10.2</vavr.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,19 @@
|
|||
package com.baeldung.aggregateEx;
|
||||
|
||||
import com.baeldung.aggregateEx.entity.Result;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class CustomMapper {
|
||||
public static <T, R> Function<T, Result<R>> mapper(Function<T, R> func) {
|
||||
return arg -> {
|
||||
Result<R> result;
|
||||
try {
|
||||
result = new Result(func.apply(arg));
|
||||
} catch (Exception e) {
|
||||
result = new Result(e);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.baeldung.aggregateEx;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collector;
|
||||
|
||||
public class ExceptionCollector<T, R> {
|
||||
private final List<R> results = new ArrayList<>();
|
||||
private final List<Exception> exceptions = new ArrayList<>();
|
||||
|
||||
private ExceptionCollector() {
|
||||
}
|
||||
|
||||
public static <T, R> Collector<T, ?, ExceptionCollector<T, R>> of(Function<T, R> mapper) {
|
||||
return Collector.of(
|
||||
ExceptionCollector::new,
|
||||
(collector, item) -> {
|
||||
try {
|
||||
R result = mapper.apply(item);
|
||||
collector.results.add(result);
|
||||
} catch (Exception e) {
|
||||
collector.exceptions.add(e);
|
||||
}
|
||||
},
|
||||
(left, right) -> {
|
||||
left.results.addAll(right.results);
|
||||
left.exceptions.addAll(right.exceptions);
|
||||
return left;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public List<R> getResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
public List<Exception> getExceptions() {
|
||||
return exceptions;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.baeldung.aggregateEx.entity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ExceptionAggregator extends RuntimeException {
|
||||
private List<Exception> exceptions;
|
||||
|
||||
public ExceptionAggregator(String message) {
|
||||
super(message);
|
||||
exceptions = new ArrayList<>();
|
||||
}
|
||||
|
||||
public List<Exception> getExceptions() {
|
||||
return exceptions;
|
||||
}
|
||||
|
||||
public Exception addException(Exception e) {
|
||||
this.addSuppressed(e);
|
||||
exceptions.add(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
public void addExceptions(List<Exception> exceptions) {
|
||||
exceptions.forEach(this::addException);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.baeldung.aggregateEx.entity;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class Result<R> {
|
||||
private Optional<R> result;
|
||||
private Optional<Exception> exception;
|
||||
|
||||
public Result(R result) {
|
||||
this.result = Optional.of(result);
|
||||
this.exception = Optional.empty();
|
||||
}
|
||||
|
||||
public Result(Exception exception) {
|
||||
this.exception = Optional.of(exception);
|
||||
this.result = Optional.empty();
|
||||
}
|
||||
|
||||
public Optional<R> getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public Optional<Exception> getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
package com.baeldung.aggregateEx;
|
||||
|
||||
import com.baeldung.aggregateEx.entity.ExceptionAggregator;
|
||||
import com.baeldung.aggregateEx.entity.Result;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import io.vavr.control.Either;
|
||||
import io.vavr.control.Try;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AggregateExceptionHandlerUnitTest {
|
||||
|
||||
private static RuntimeException process(String str) {
|
||||
try {
|
||||
Integer.parseInt(str);
|
||||
return null;
|
||||
} catch (NumberFormatException e) {
|
||||
return new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object transform(String str) {
|
||||
try {
|
||||
return (Integer.parseInt(str));
|
||||
} catch (NumberFormatException e) {
|
||||
return new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenExtractedMethod_whenFoundNonInt_thenAggregateException() {
|
||||
String[] strings = {"1", "2", "3", "a", "b", "c"};
|
||||
RuntimeException runEx = Arrays.stream(strings)
|
||||
.map(AggregateExceptionHandlerUnitTest::process)
|
||||
.filter(Objects::nonNull)
|
||||
.reduce(new RuntimeException("Errors Occurred"), (o1, o2) -> {
|
||||
o1.addSuppressed(o2);
|
||||
return o1;
|
||||
});
|
||||
assertEquals("Errors Occurred", runEx.getMessage());
|
||||
assertEquals(3, runEx.getSuppressed().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTryCatchInPipeline_whenFoundNonInts_thenAggregateException() {
|
||||
String[] strings = {"1", "2", "3", "a", "b", "c"};
|
||||
RuntimeException runEx = Arrays.stream(strings)
|
||||
.map(str -> {
|
||||
try {
|
||||
Integer.parseInt(str);
|
||||
return null;
|
||||
} catch (NumberFormatException e) {
|
||||
return new RuntimeException(e);
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.reduce(new RuntimeException("Errors Occurred"), (o1, o2) -> {
|
||||
o1.addSuppressed(o2);
|
||||
return o1;
|
||||
});
|
||||
assertEquals("Errors Occurred", runEx.getMessage());
|
||||
assertEquals(3, runEx.getSuppressed().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenFoundNonInts_thenAggregateExceptionAndReturnOutput() {
|
||||
String[] strings = {"1", "2", "3", "a", "b", "c"};
|
||||
Map resultMap = Arrays.stream(strings)
|
||||
.map(AggregateExceptionHandlerUnitTest::transform)
|
||||
.collect(Collectors.partitioningBy(o -> o instanceof RuntimeException, Collectors.toList()));
|
||||
RuntimeException ex = null;
|
||||
if (resultMap.containsKey(Boolean.TRUE)) {
|
||||
List<RuntimeException> exs = (List<RuntimeException>) resultMap.get(Boolean.TRUE);
|
||||
ex = exs.stream()
|
||||
.reduce(
|
||||
new RuntimeException("Errors Occurred"), (o1, o2) -> {
|
||||
o1.addSuppressed(o2);
|
||||
return o1;
|
||||
});
|
||||
}
|
||||
assertEquals("Errors Occurred", ex.getMessage());
|
||||
assertEquals(3, ex.getSuppressed().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenWrapFunction_whenFoundNonInts_thenAggregateException() throws ExceptionAggregator {
|
||||
String[] strings = {"1", "2", "3", "a", "b", "c"};
|
||||
Map<Boolean, List<Result<Integer>>> resultmap = Arrays.stream(strings)
|
||||
.map(CustomMapper.mapper(Integer::parseInt))
|
||||
.collect(Collectors.partitioningBy(r -> r.getException().isEmpty(), Collectors.toList()));
|
||||
|
||||
if (resultmap.containsKey(Boolean.FALSE)) {
|
||||
List<Result<Integer>> resultList = resultmap.get(Boolean.FALSE);
|
||||
List<Exception> exceptionList = resultList.stream()
|
||||
.map(opex -> opex.getException().get())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
assertThrows(ExceptionAggregator.class, () -> handleExceptions(exceptionList));
|
||||
}
|
||||
}
|
||||
|
||||
private void handleExceptions(List<Exception> exceptions) throws ExceptionAggregator {
|
||||
ExceptionAggregator exceptionAggregator = new ExceptionAggregator("Errors occurred");
|
||||
exceptionAggregator.addExceptions(exceptions);
|
||||
throw exceptionAggregator;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenExCollector_whenFoundNonInts_thenAggregateException() throws ExceptionAggregator {
|
||||
String[] strings = {"1", "2", "3", "a", "b", "c"};
|
||||
ExceptionCollector exCollector = Arrays.stream(strings)
|
||||
.collect(ExceptionCollector.of(Integer::parseInt));
|
||||
List<Integer> output = exCollector.getResults();
|
||||
List<RuntimeException> runEx = exCollector.getExceptions();
|
||||
assertEquals(3, runEx.size());
|
||||
}
|
||||
|
||||
private static Either<RuntimeException, Integer> processAndReturnEither(String str) {
|
||||
Either<RuntimeException, Integer> either = null;
|
||||
try {
|
||||
either = Either.right(Integer.parseInt(str));
|
||||
} catch (NumberFormatException e) {
|
||||
either = Either.left(new RuntimeException(e));
|
||||
}
|
||||
return either;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVavrEither_whenFoundNonInts_thenAggregateException() {
|
||||
List<String> strings = List.of("1", "2", "3", "a", "b", "c");
|
||||
Map<Boolean, List<Either<RuntimeException, Integer>>> map = strings.stream()
|
||||
.map(str -> processAndReturnEither(str))
|
||||
.collect(Collectors.partitioningBy((t) -> t.isLeft(), Collectors.toList()));
|
||||
|
||||
RuntimeException runEx = map.get(Boolean.TRUE)
|
||||
.stream().map(either -> either.getLeft())
|
||||
.reduce(new RuntimeException("Errors Occurred"), (o1, o2) -> {
|
||||
o1.addSuppressed(o2);
|
||||
return o1;
|
||||
});
|
||||
assertEquals(3, runEx.getSuppressed().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVavrTry_whenFoundNonInts_thenAggregateException() {
|
||||
List<String> strings = List.of("1", "2", "3", "a", "b", "c");
|
||||
Map<Boolean, List<Try<Integer>>> map = strings.stream()
|
||||
.map(str -> Try.of(() -> Integer.parseInt(str)))
|
||||
.collect(Collectors.partitioningBy((t) -> t.isFailure(), Collectors.toList()));
|
||||
Throwable runEx = map.get(Boolean.TRUE).stream()
|
||||
.map(t -> t.getCause())
|
||||
.reduce(new RuntimeException("Errors Occurred"), (o1, o2) -> {
|
||||
o1.addSuppressed(o2);
|
||||
return o1;
|
||||
});
|
||||
assertEquals(3, runEx.getSuppressed().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVavrEitherAndTry_whenFoundNonInts_thenAggregateException() {
|
||||
List<String> strings = List.of("1", "2", "3", "a", "b", "c");
|
||||
Map<Boolean, List<Either<Throwable, Integer>>> map = strings.stream()
|
||||
.map(str -> Try.of(() -> Integer.parseInt(str)).toEither())
|
||||
.collect(Collectors.partitioningBy(Either::isLeft, Collectors.toList()));
|
||||
Throwable runEx = map.get(Boolean.TRUE).stream()
|
||||
.map(either -> either.getLeft())
|
||||
.reduce(new RuntimeException("Errors Occurred"), (o1, o2) -> {
|
||||
o1.addSuppressed(o2);
|
||||
return o1;
|
||||
});
|
||||
assertEquals(3, runEx.getSuppressed().length);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue