Skip to content

Commit a97d6ec

Browse files
committed
Changing the approach
Let the exception be suppressed, but removing the cause of the suppressed exception by create a new one.
1 parent 9139204 commit a97d6ec

File tree

4 files changed

+102
-19
lines changed

4 files changed

+102
-19
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
package org.neo4j.driver.internal.util;
20+
21+
import java.lang.reflect.Constructor;
22+
import java.lang.reflect.InvocationTargetException;
23+
import java.util.Optional;
24+
import java.util.function.Function;
25+
26+
public class Exceptions
27+
{
28+
public static Optional<Throwable> copyWithoutCause (Throwable ex) {
29+
return getConstructor(ex.getClass(), String.class)
30+
.flatMap( copy( ex ) );
31+
}
32+
33+
private static Optional<Constructor<? extends Throwable>> getConstructor (Class<? extends Throwable> clazz, Class<?> ... paramTypes)
34+
{
35+
try
36+
{
37+
return Optional.of( clazz.getConstructor( paramTypes ) );
38+
}
39+
catch ( NoSuchMethodException ignored )
40+
{
41+
return Optional.empty();
42+
}
43+
}
44+
45+
private static Function<Constructor<? extends Throwable>, Optional<Throwable>> copy(Throwable ex) {
46+
return constructor ->
47+
{
48+
try
49+
{
50+
Throwable result = constructor.newInstance( ex.getMessage() );
51+
result.setStackTrace( ex.getStackTrace() );
52+
for (Throwable suppressed: ex.getSuppressed()) {
53+
result.addSuppressed( suppressed );
54+
}
55+
return Optional.of( result );
56+
}
57+
catch ( IllegalAccessException | InstantiationException | InvocationTargetException ignore )
58+
{
59+
return Optional.empty();
60+
}
61+
};
62+
}
63+
64+
}

driver/src/main/java/org/neo4j/driver/internal/util/Futures.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,16 @@ public static CompletionException combineErrors( Throwable error1, Throwable err
205205
{
206206
Throwable cause1 = completionExceptionCause( error1 );
207207
Throwable cause2 = completionExceptionCause( error2 );
208-
if (cause1 != cause2.getCause() && cause1.getCause() != cause2) {
208+
if ( cause1.getCause() != cause2 )
209+
{
210+
if ( cause1 == cause2.getCause() )
211+
{
212+
cause2 = Exceptions.copyWithoutCause( cause2 )
213+
.orElse( cause2 );
214+
}
209215
addSuppressed( cause1, cause2 );
210-
} else if (cause1 == cause2.getCause()) {
211-
return asCompletionException( cause2 );
212216
}
217+
213218
return asCompletionException( cause1 );
214219
}
215220
else if ( error1 != null )

driver/src/test/java/org/neo4j/driver/internal/util/FuturesTest.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import static org.junit.jupiter.api.Assertions.assertFalse;
4646
import static org.junit.jupiter.api.Assertions.assertNotEquals;
4747
import static org.junit.jupiter.api.Assertions.assertNull;
48+
import static org.junit.jupiter.api.Assertions.assertSame;
4849
import static org.junit.jupiter.api.Assertions.assertThrows;
4950
import static org.junit.jupiter.api.Assertions.assertTrue;
5051
import static org.neo4j.driver.internal.util.Matchers.blockingOperationInEventLoopError;
@@ -315,18 +316,24 @@ void shouldCombineTwoErrors()
315316
}
316317

317318
@Test
318-
void shouldCombineTwoErrorsUsingErrorCause2()
319+
void shouldCombineTwoErrorsUsingErrorCause1()
319320
{
320321
RuntimeException error1 = new RuntimeException( "Error1" );
321322
RuntimeException error2Cause = new RuntimeException( "Error2", error1 );
322323
CompletionException error2 = new CompletionException( error2Cause );
323324

324325
CompletionException combined = Futures.combineErrors( error1, error2 );
325326

326-
assertEquals( error2Cause, combined.getCause() );
327+
assertEquals( error1, combined.getCause() );
327328

328329
assertNoCircularReferences( combined );
329-
assertArrayEquals( new Throwable[]{}, combined.getCause().getSuppressed() );
330+
331+
assertEquals(1 , combined.getCause().getSuppressed().length );
332+
Throwable suppressed = combined.getCause().getSuppressed()[0];
333+
assertEquals( error2Cause.getClass(), suppressed.getClass());
334+
assertEquals( error2Cause.getMessage(), suppressed.getMessage() );
335+
assertArrayEquals( error2Cause.getStackTrace(), suppressed.getStackTrace() );
336+
assertArrayEquals( error2Cause.getSuppressed(), suppressed.getSuppressed() );
330337
}
331338

332339
@Test
@@ -338,10 +345,9 @@ void shouldCombineTwoErrorsUsingError1()
338345

339346
CompletionException combined = Futures.combineErrors( error1, error2 );
340347

341-
assertEquals( error1, combined.getCause() );
348+
assertSame( error1, combined.getCause() );
342349

343350
assertNoCircularReferences( combined );
344-
assertArrayEquals( new Throwable[]{}, combined.getCause().getSuppressed() );
345351
}
346352

347353

driver/src/test/java/org/neo4j/driver/util/TestUtil.java

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -654,28 +654,36 @@ private static void assertNoCircularReferences(Throwable ex, List<Throwable> lis
654654
{
655655
list.add( ex );
656656
if (ex.getCause() != null ) {
657-
if (list.contains( ex.getCause() )) {
658-
throw new AssertionError("Circular reference detected", ex.getCause());
657+
if ( containsReference( list, ex.getCause() ) )
658+
{
659+
throw new AssertionError( "Circular reference detected", ex.getCause() );
659660
}
660-
assertNoCircularReferences(ex.getCause(), list);
661+
assertNoCircularReferences( ex.getCause(), list );
661662
}
662-
for ( Throwable suppressed: ex.getSuppressed() )
663+
for ( Throwable suppressed : ex.getSuppressed() )
663664
{
664-
if(list.contains( suppressed )) {
665-
throw new AssertionError("Circular reference detected", suppressed);
665+
if ( containsReference( list, suppressed ) )
666+
{
667+
throw new AssertionError( "Circular reference detected", suppressed );
666668
}
667669
assertNoCircularReferences( suppressed, list );
668670
}
669671
}
670672

673+
private static <T> boolean containsReference( List<T> list, T object )
674+
{
675+
return list.stream()
676+
.anyMatch( element -> element == object );
677+
}
678+
671679
private static void setupSuccessfulPullAll( Connection connection, String query )
672680
{
673681
doAnswer( invocation ->
674-
{
675-
ResponseHandler handler = invocation.getArgument( 3 );
676-
handler.onSuccess( emptyMap() );
677-
return null;
678-
} ).when( connection ).writeAndFlush( argThat( runMessageWithQueryMatcher( query ) ), any(), any(), any() );
682+
{
683+
ResponseHandler handler = invocation.getArgument( 3 );
684+
handler.onSuccess( emptyMap() );
685+
return null;
686+
} ).when( connection ).writeAndFlush( argThat( runMessageWithQueryMatcher( query ) ), any(), any(), any() );
679687
}
680688

681689
private static void setupSuccessResponse( Connection connection, Class<? extends Message> messageType )

0 commit comments

Comments
 (0)