Repository: netflix/dgs-framework
Issue: bug: dgsQueryExecutor.executeAndExtractJsonPathAsObject cannot deserialize DateTime scalars

## Expected behavior

The framework should serialize the json response to an object, including DateTime scalar values.

## Actual behavior

Jackson's ObjectMapper does not know about the scalar and a DgsQueryExecutionDataExtractionException is thrown.

## Steps to reproduce

Please see the issue I opened in [dgs-examples-java](https://github.com/Netflix/dgs-examples-java/issues/7).


Changed files:
graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DefaultDgsQueryExecutor.kt
graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/internal/DefaultDgsQueryExecutorTest.kt

diff --git a/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DefaultDgsQueryExecutor.kt b/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DefaultDgsQueryExecutor.kt
index 7f725024..085daf1a 100644
--- a/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DefaultDgsQueryExecutor.kt
+++ b/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DefaultDgsQueryExecutor.kt
@@ -18,6 +18,7 @@ package com.netflix.graphql.dgs.internal
 
 import com.fasterxml.jackson.databind.DeserializationFeature
 import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
 import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
 import com.jayway.jsonpath.*
 import com.jayway.jsonpath.spi.json.JacksonJsonProvider
@@ -64,6 +65,7 @@ class DefaultDgsQueryExecutor(
                 .mappingProvider(
                     JacksonMappingProvider(
                         jacksonObjectMapper()
+                            .registerModule(JavaTimeModule())
                             .enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE)
                             .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                     )
diff --git a/graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/internal/DefaultDgsQueryExecutorTest.kt b/graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/internal/DefaultDgsQueryExecutorTest.kt
index 154840d2..d39ecd8b 100644
--- a/graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/internal/DefaultDgsQueryExecutorTest.kt
+++ b/graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/internal/DefaultDgsQueryExecutorTest.kt
@@ -21,6 +21,7 @@ import com.jayway.jsonpath.spi.mapper.MappingException
 import com.netflix.graphql.dgs.DgsComponent
 import com.netflix.graphql.dgs.DgsData
 import com.netflix.graphql.dgs.DgsScalar
+import com.netflix.graphql.dgs.LocalDateTimeScalar
 import com.netflix.graphql.dgs.exceptions.DgsQueryExecutionDataExtractionException
 import com.netflix.graphql.dgs.exceptions.QueryException
 import graphql.execution.AsyncExecutionStrategy
@@ -36,6 +37,7 @@ import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.assertThrows
 import org.junit.jupiter.api.extension.ExtendWith
 import org.springframework.context.ApplicationContext
+import java.time.LocalDateTime
 import java.util.*
 import java.util.function.Supplier
 
@@ -70,7 +72,7 @@ internal class DefaultDgsQueryExecutorTest {
         val moviesFetcher = object : Any() {
             @DgsData(parentType = "Query", field = "movies")
             fun movies(): List<Movie> {
-                return listOf(Movie("Extraction"), Movie("Da 5 Bloods"))
+                return listOf(Movie("Extraction", LocalDateTime.MIN), Movie("Da 5 Bloods", LocalDateTime.MAX))
             }
         }
 
@@ -82,7 +84,7 @@ internal class DefaultDgsQueryExecutorTest {
         }
 
         every { applicationContextMock.getBeansWithAnnotation(DgsComponent::class.java) } returns mapOf(Pair("helloFetcher", fetcher), Pair("numbersFetcher", numbersFetcher), Pair("moviesFetcher", moviesFetcher), Pair("withErrorFetcher", fetcherWithError))
-        every { applicationContextMock.getBeansWithAnnotation(DgsScalar::class.java) } returns emptyMap()
+        every { applicationContextMock.getBeansWithAnnotation(DgsScalar::class.java) } returns mapOf(Pair("DateTimeScalar", LocalDateTimeScalar()))
         every { dgsDataLoaderProvider.buildRegistryWithContextSupplier(any<Supplier<Any>>()) } returns DataLoaderRegistry()
 
         val provider = DgsSchemaProvider(
@@ -103,11 +105,14 @@ internal class DefaultDgsQueryExecutorTest {
             
             type Movie { 
                 title: String
+                releaseDate: DateTime
             }
             
             type Person {
                 name: String
             }
+
+            scalar DateTime
             """.trimIndent()
         )
 
@@ -147,13 +152,14 @@ internal class DefaultDgsQueryExecutorTest {
         val movies = dgsQueryExecutor!!.executeAndExtractJsonPath<List<Map<String, Any>>>(
             """
             {
-                movies { title } 
+                movies { title releaseDate }
             }
             """.trimIndent(),
             "data.movies"
         )
 
         assertThat(movies[0]["title"]).isEqualTo("Extraction")
+        assertThat(LocalDateTime.parse(movies[0]["releaseDate"] as CharSequence)).isEqualTo(LocalDateTime.MIN)
     }
 
     @Test
@@ -161,13 +167,14 @@ internal class DefaultDgsQueryExecutorTest {
         val movie = dgsQueryExecutor!!.executeAndExtractJsonPath<Map<String, Any>>(
             """
             {
-                movies { title } 
+                movies { title releaseDate }
             }
             """.trimIndent(),
             "data.movies[0]"
         )
 
         assertThat(movie["title"]).isEqualTo("Extraction")
+        assertThat(LocalDateTime.parse(movie["releaseDate"] as CharSequence)).isEqualTo(LocalDateTime.MIN)
     }
 
     @Test
@@ -175,13 +182,14 @@ internal class DefaultDgsQueryExecutorTest {
         val movie = dgsQueryExecutor!!.executeAndExtractJsonPathAsObject(
             """
             {
-                movies { title } 
+                movies { title releaseDate }
             }
             """.trimIndent(),
             "data.movies[0]", Movie::class.java
         )
 
         assertThat(movie.title).isEqualTo("Extraction")
+        assertThat(movie.releaseDate).isEqualTo(LocalDateTime.MIN)
     }
 
     @Test
@@ -189,7 +197,7 @@ internal class DefaultDgsQueryExecutorTest {
         val person = dgsQueryExecutor!!.executeAndExtractJsonPathAsObject(
             """
             {
-                movies { title } 
+                movies { title releaseDate }
             }
             """.trimIndent(),
             "data.movies", object : TypeRef<List<Movie>>() {}
@@ -260,7 +268,7 @@ internal class DefaultDgsQueryExecutorTest {
         val context = dgsQueryExecutor!!.executeAndGetDocumentContext(
             """
             {
-                movies { title }
+                movies { title releaseDate }
             }
             """.trimIndent()
         )
@@ -285,6 +293,7 @@ internal class DefaultDgsQueryExecutorTest {
         assertThat(movie).isNotNull
     }
 
+    @Test
     fun withFieldNamedErrors() {
 
         val context = dgsQueryExecutor!!.executeAndGetDocumentContext(
@@ -300,4 +309,4 @@ internal class DefaultDgsQueryExecutorTest {
     }
 }
 
-data class Movie(val title: String)
+data class Movie(val title: String, val releaseDate: LocalDateTime?)