1+ package com .baeldung .aggregateexception ;
2+
3+ import com .baeldung .aggregateexception .entity .Result ;
4+ import io .vavr .control .Either ;
5+ import io .vavr .control .Try ;
6+ import org .junit .Test ;
7+ import org .slf4j .Logger ;
8+ import org .slf4j .LoggerFactory ;
9+
10+ import java .util .Arrays ;
11+ import java .util .List ;
12+ import java .util .Map ;
13+ import java .util .Objects ;
14+ import java .util .stream .Collectors ;
15+
16+ import static org .junit .Assert .assertEquals ;
17+
18+
19+ public class AggregateExceptionHandlerUnitTest {
20+ private static final Logger logger = LoggerFactory .getLogger (AggregateExceptionHandlerUnitTest .class );
21+
22+ @ Test
23+ public void givenExtractedMethod_whenFoundEx_thenSuppressExIntoRuntimeEx () {
24+ String [] strings = {"1" , "2" , "3" , "a" , "b" , "c" };
25+ RuntimeException runEx = Arrays .stream (strings )
26+ .map (str -> callProcessThrowsExAndNoOutput (str ))
27+ .filter (Objects ::nonNull )
28+ .reduce (new RuntimeException ("Errors Occurred" ), (o1 , o2 ) -> {
29+ o1 .addSuppressed (o2 );
30+ return o1 ;
31+ });
32+ processExceptions (runEx );
33+ assertEquals ("Errors Occurred" , runEx .getMessage ());
34+ assertEquals (3 , runEx .getSuppressed ().length );
35+ }
36+ @ Test
37+ public void givenTryCatchInPipeline_whenFoundEx_thenSuppressExIntoRuntimeEx () {
38+ String [] strings = {"1" , "2" , "3" , "a" , "b" , "c" };
39+ RuntimeException runEx = Arrays .stream (strings ).map (str -> {
40+ try {
41+ processThrowsExAndNoOutput (str );
42+ return null ;
43+ } catch (RuntimeException e ) {
44+ return e ;
45+ }
46+ }).filter (Objects ::nonNull )
47+ .collect (Collectors .collectingAndThen (Collectors .toList (), list -> {
48+ RuntimeException runtimeException = new RuntimeException ("Errors Occurred" );
49+ list .forEach (runtimeException ::addSuppressed );
50+ return runtimeException ;
51+ }));
52+ processExceptions (runEx );
53+ assertEquals ("Errors Occurred" , runEx .getMessage ());
54+ assertEquals (3 , runEx .getSuppressed ().length );
55+ }
56+
57+ @ Test
58+ public void givenProcessMethod_whenStreamResultHasExAndOutput_thenHandleExceptionListAndOutputList () {
59+ List <String > strings = List .of ("1" , "2" , "3" , "a" , "b" , "c" );
60+ Map map = strings .stream ()
61+ .map (s -> processReturnsExAndOutput (s ))
62+ .collect (Collectors .partitioningBy (o -> o instanceof RuntimeException , Collectors .toList ()));
63+
64+ List <RuntimeException > exceptions = (List <RuntimeException >)map .getOrDefault (Boolean .TRUE , List .of ());
65+ List <Integer > results = (List <Integer >)map .getOrDefault (Boolean .FALSE , List .of ());
66+ handleExceptionsAndOutputs (exceptions , results );
67+ }
68+
69+ @ Test
70+ public void givenCustomMapper_whenStreamResultHasExAndSuccess_thenHandleExceptionListAndOutputList () {
71+ List <String > strings = List .of ("1" , "2" , "3" , "a" , "b" , "c" );
72+ strings .stream ()
73+ .map (CustomMapper .mapper (Integer ::parseInt ))
74+ .collect (Collectors .collectingAndThen (Collectors .toList (), list -> handleErrorsAndOutputForResult (list )));
75+ }
76+
77+ @ Test
78+ public void givenCustomCollector_whenStreamResultHasExAndSuccess_thenHandleAggrExceptionAndResults () {
79+ String [] strings = {"1" , "2" , "3" , "a" , "b" , "c" };
80+ Arrays .stream (strings )
81+ .collect (Collectors .collectingAndThen (CustomCollector .of (Integer ::parseInt ),
82+ col -> handleExAndResults (col .getExceptions (), col .getResults ())));
83+ }
84+
85+ @ Test
86+ public void givenVavrEitherAndTry_whenStreamResultHasExAndSuccess_thenHandleExceptionListAndOutputList () {
87+ List <String > strings = List .of ("1" , "2" , "3" , "a" , "b" , "c" );
88+ strings .stream ()
89+ .map (str -> Try .of (() -> Integer .parseInt (str )).toEither ())
90+ .collect (Collectors .collectingAndThen (Collectors .partitioningBy (Either ::isLeft , Collectors .toList ()),
91+ map -> handleErrorsAndOutputForEither (map )));
92+ }
93+
94+ private static void processThrowsExAndNoOutput (String input ) {
95+ //throw exception when input is "a", "b", "c"
96+ if (input .matches ("[a-c]" )) {
97+ throw new RuntimeException ("Downstream method throws exception for " + input );
98+ }
99+ }
100+ private static RuntimeException callProcessThrowsExAndNoOutput (String input ) {
101+ try {
102+ processThrowsExAndNoOutput (input );
103+ return null ;
104+ } catch (RuntimeException e ) {
105+ return e ;
106+ }
107+ }
108+
109+ private static Object processReturnsExAndOutput (String input ) {
110+ logger .info ("call a downstream method that returns an Integer" );
111+ try {
112+ return Integer .parseInt (input );
113+ } catch (Exception e ) {
114+ return new RuntimeException ("Exception in processWithReturnOutput for " + input , e );
115+ }
116+ }
117+
118+ private static void processExceptions (Throwable throwable ) {
119+ logger .error ("Process Exception" + throwable .getMessage ());
120+ }
121+
122+ private static void handleExceptionsAndOutputs (List <RuntimeException > exs , List <Integer > output ) {
123+ logger .info ("number of exceptions " + exs .size () + " number of outputs " + output .size ());
124+ }
125+
126+ private static String handleExAndResults (List <Throwable > ex , List <Integer > results ) {
127+ logger .info ("handle aggregated exceptions and results" + ex .size () + " " + results .size ());
128+ return "Exceptions and Results Handled" ;
129+ }
130+
131+ private static String handleErrorsAndOutputForEither (Map <Boolean , List <Either <Throwable , Integer >>> map ) {
132+ logger .info ("handle errors and output" );
133+ map .getOrDefault (Boolean .TRUE , List .of ()).forEach (either -> logger .error ("Process Exception " + either .getLeft ()));
134+
135+ map .getOrDefault (Boolean .FALSE , List .of ()).forEach (either -> logger .info ("Process Result " + either .get ()));
136+ return "Errors and Output Handled" ;
137+ }
138+
139+ private static String handleErrorsAndOutputForResult (List <Result <Integer , Throwable >> successAndErrors ) {
140+ logger .info ("handle errors and output" );
141+ successAndErrors .forEach (result -> {
142+ if (result .getException ().isPresent ()) {
143+ logger .error ("Process Exception " + result .getException ().get ());
144+ } else {
145+ logger .info ("Process Result" + result .getResult ().get ());
146+ }
147+ });
148+ return "Errors and Output Handled" ;
149+ }
150+ }
0 commit comments