Skip to content

Commit a0c26c0

Browse files
rharrisodariuszkuc
authored andcommitted
FunctionDataFetch throws InvocationException.cause property when available (#225)
* FunctionDataFetch throws InvocationException cause property when available. This allows thrown `GraphQLException` instances to be handled by `graph-java` as it would if thrown directly by a `DataFetcher` lambda. * Include necessary test modules * Fix linting issues * Just return a string
1 parent bf01d01 commit a0c26c0

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

src/main/kotlin/com/expedia/graphql/execution/FunctionDataFetcher.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import graphql.schema.DataFetchingEnvironment
1111
import kotlinx.coroutines.GlobalScope
1212
import kotlinx.coroutines.async
1313
import kotlinx.coroutines.future.asCompletableFuture
14+
import java.lang.reflect.InvocationTargetException
1415
import kotlin.reflect.KFunction
1516
import kotlin.reflect.KParameter
1617
import kotlin.reflect.full.callSuspend
@@ -46,7 +47,11 @@ class FunctionDataFetcher(
4647
fn.callSuspend(it, *parameterValues)
4748
}.asCompletableFuture()
4849
} else {
49-
fn.call(it, *parameterValues)
50+
try {
51+
return fn.call(it, *parameterValues)
52+
} catch (exception: InvocationTargetException) {
53+
throw exception.cause ?: exception
54+
}
5055
}
5156
}
5257
}

src/test/kotlin/com/expedia/graphql/execution/FunctionDataFetcherTest.kt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.expedia.graphql.execution
22

33
import com.expedia.graphql.annotations.GraphQLContext
44
import com.expedia.graphql.exceptions.CouldNotCastArgumentException
5+
import graphql.GraphQLException
56
import graphql.schema.DataFetchingEnvironment
67
import io.mockk.every
78
import io.mockk.mockk
@@ -12,7 +13,9 @@ import java.util.concurrent.CompletableFuture
1213
import kotlin.test.assertEquals
1314
import kotlin.test.assertFailsWith
1415
import kotlin.test.assertNull
16+
import kotlin.test.assertNotNull
1517
import kotlin.test.assertTrue
18+
import kotlin.test.assertFalse
1619

1720
internal class FunctionDataFetcherTest {
1821

@@ -31,6 +34,13 @@ internal class FunctionDataFetcherTest {
3134
delay(10)
3235
string
3336
}
37+
38+
fun throwException() { throw GraphQLException("Test Exception") }
39+
40+
suspend fun suspendThrow(): String = coroutineScope {
41+
delay(10)
42+
throw GraphQLException("Suspended Exception")
43+
}
3444
}
3545

3646
@Test
@@ -126,4 +136,34 @@ internal class FunctionDataFetcherTest {
126136
assertTrue(result is CompletableFuture<*>)
127137
assertEquals(expected = "hello", actual = result.get())
128138
}
139+
140+
@Test
141+
fun `throwException function propagates the original exception`() {
142+
val dataFetcher = FunctionDataFetcher(target = MyClass(), fn = MyClass::throwException)
143+
val mockEnvironmet: DataFetchingEnvironment = mockk()
144+
145+
try {
146+
dataFetcher.get(mockEnvironmet)
147+
assertFalse(true, "Should not be here")
148+
} catch (e: Exception) {
149+
assertEquals(e.message, "Test Exception")
150+
}
151+
}
152+
153+
@Test
154+
fun `suspendThrow throws exception when resolved`() {
155+
val dataFetcher = FunctionDataFetcher(target = MyClass(), fn = MyClass::suspendThrow)
156+
val mockEnvironmet: DataFetchingEnvironment = mockk()
157+
158+
try {
159+
val result = dataFetcher.get(mockEnvironmet)
160+
assertTrue(result is CompletableFuture<*>)
161+
result.get()
162+
assertFalse(true, "Should not be here")
163+
} catch (e: Exception) {
164+
val message = e.message
165+
assertNotNull(message)
166+
assertTrue(message.endsWith("Suspended Exception"))
167+
}
168+
}
129169
}

0 commit comments

Comments
 (0)