Repository: netflix/dgs-framework
Issue: bug: If the input is a list of enums, the deserialized list passed to the fetcher still contains strings.

If the input is a list of enums, the deserialized list passed to the fetcher still contains strings, e.g.:

```
Query {
  lookup(types: [MyTypeEnum!]): [Result]
}

enum MyTypeEnum {
  TYPE1,
  TYPE2
}
```

This will fail:
```
query TestQuery {
  lookup(types: [TYPE1])
}
```

However if you nest the enum inside another input object the deserialization does work correctly:
```
query {
  lookup(types: MyLookupType): [Result]
}

input MyLookupType {
  types: [MyTypeEnum!]!
}

enum MyTypeEnum {
  TYPE1,
  TYPE2
}
```

this will work, nested list of enums will be deserialized properly when calling the fetcher method:
```
Query TestQuery {
  lookup(types: { types: [TYPE1]})
}
```

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

diff --git a/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DataFetcherInvoker.kt b/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DataFetcherInvoker.kt
index 31884e2b..7af7b4c9 100644
--- a/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DataFetcherInvoker.kt
+++ b/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DataFetcherInvoker.kt
@@ -190,22 +190,23 @@ class DataFetcherInvoker(
         val collectionType = annotation.collectionType.java
         val parameterValue: Any? = environment.getArgument(parameterName)
 
-        val convertValue: Any? = if (parameterValue is List<*> && collectionType != Object::class.java) {
-            try {
-                // Return a list of elements that are converted to their collection type, e.e.g. List<Person>, List<String> etc.
-                parameterValue.map { item -> convertValue(item, parameter, collectionType) }.toList()
-            } catch (ex: Exception) {
-                throw DgsInvalidInputArgumentException(
-                    "Specified type '$collectionType' is invalid for $parameterName.",
-                    ex
-                )
+        val convertValue: Any? =
+            if (parameterValue is List<*> && collectionType != Object::class.java) {
+                try {
+                    // Return a list of elements that are converted to their collection type, e.e.g. List<Person>, List<String> etc.
+                    parameterValue.map { item -> convertValue(item, parameter, collectionType) }.toList()
+                } catch (ex: Exception) {
+                    throw DgsInvalidInputArgumentException(
+                        "Specified type '$collectionType' is invalid for $parameterName.",
+                        ex
+                    )
+                }
+            } else if (parameterValue is Map<*, *> && parameter.type.isAssignableFrom(Map::class.java)) {
+                parameterValue
+            } else {
+                // Return the converted value mapped to the defined type
+                convertValue(parameterValue, parameter, collectionType)
             }
-        } else if (parameterValue is Map<*, *> && parameter.type.isAssignableFrom(Map::class.java)) {
-            parameterValue
-        } else {
-            // Return the converted value mapped to the defined type
-            convertValue(parameterValue, parameter, collectionType)
-        }
 
         val paramType = parameter.type
         val optionalValue = getValueAsOptional(convertValue, parameter)
@@ -239,8 +240,15 @@ class DataFetcherInvoker(
             } else {
                 InputObjectMapper.mapToJavaObject(parameterValue as Map<String, *>, targetType)
             }
-        } else if (parameter.type.isEnum && parameterValue !== null) {
-            (parameter.type.enumConstants as Array<Enum<*>>).find { it.name == parameterValue }
+        } else if ((parameter.type.isEnum || collectionType?.isEnum == true) && parameterValue != null) {
+            val enumConstants: Array<Enum<*>> =
+                if (parameter.type.isEnum) {
+                    parameter.type.enumConstants as Array<Enum<*>>
+                } else {
+                    collectionType?.enumConstants as Array<Enum<*>>
+                }
+
+            enumConstants.find { it.name == parameterValue }
                 ?: throw DgsInvalidInputArgumentException("Invalid enum value '$parameterValue for enum type ${parameter.type.name}")
         } else if (parameter.type == Optional::class.java) {
             val targetType: Class<*> = if (collectionType != Object::class.java) {
diff --git a/graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/internal/InputArgumentTest.kt b/graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/internal/InputArgumentTest.kt
index d24ce9a5..d14e90f8 100644
--- a/graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/internal/InputArgumentTest.kt
+++ b/graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/internal/InputArgumentTest.kt
@@ -1386,7 +1386,7 @@ internal class InputArgumentTest {
     }
 
     @Test
-    fun `Kotlin enum @InputArgument`() {
+    fun `Kotlin enum in @InputArgument`() {
         val schema = """
             type Query {
                 hello(type:GreetingType): String
@@ -1407,12 +1407,7 @@ internal class InputArgumentTest {
             }
         }
 
-        every { applicationContextMock.getBeansWithAnnotation(DgsComponent::class.java) } returns mapOf(
-            Pair(
-                "helloFetcher",
-                fetcher
-            )
-        )
+        every { applicationContextMock.getBeansWithAnnotation(DgsComponent::class.java) } returns mapOf("helloFetcher" to fetcher)
         every { applicationContextMock.getBeansWithAnnotation(DgsScalar::class.java) } returns emptyMap()
         every { applicationContextMock.getBeansWithAnnotation(DgsDirective::class.java) } returns emptyMap()
 
@@ -1427,7 +1422,7 @@ internal class InputArgumentTest {
     }
 
     @Test
-    fun `Kotlin Optional enum @InputArgument`() {
+    fun `Kotlin Optional enum in @InputArgument`() {
         val schema = """
             type Query {
                 hello(type:GreetingType): String
@@ -1448,12 +1443,7 @@ internal class InputArgumentTest {
             }
         }
 
-        every { applicationContextMock.getBeansWithAnnotation(DgsComponent::class.java) } returns mapOf(
-            Pair(
-                "helloFetcher",
-                fetcher
-            )
-        )
+        every { applicationContextMock.getBeansWithAnnotation(DgsComponent::class.java) } returns mapOf("helloFetcher" to fetcher)
         every { applicationContextMock.getBeansWithAnnotation(DgsScalar::class.java) } returns emptyMap()
         every { applicationContextMock.getBeansWithAnnotation(DgsDirective::class.java) } returns emptyMap()
 
@@ -1467,6 +1457,51 @@ internal class InputArgumentTest {
         verify { applicationContextMock.getBeansWithAnnotation(DgsComponent::class.java) }
     }
 
+    @Test
+    fun `List of enums as @InputArgument`() {
+        val schema = """
+            type Query {
+                khello(input: [GreetingType]): String
+                jhello(input: [GreetingType]): String
+            }
+            
+            enum GreetingType {          
+                FRIENDLY
+                POLITE
+            }
+        """.trimIndent()
+
+        val fetcher = object : Any() {
+
+            @DgsQuery
+            fun khello(@InputArgument(collectionType = KGreetingType::class) input: List<KGreetingType>): String {
+                assertThat(input).isNotEmpty.hasOnlyElementsOfType(KGreetingType::class.java)
+                return "Hello, this is a $input greeting"
+            }
+            @DgsQuery
+            fun jhello(@InputArgument(collectionType = JGreetingType::class) input: List<JGreetingType>): String {
+                assertThat(input).isNotEmpty.hasOnlyElementsOfType(JGreetingType::class.java)
+                return "Hello, this is a $input greeting"
+            }
+        }
+
+        every { applicationContextMock.getBeansWithAnnotation(DgsComponent::class.java) } returns mapOf("helloFetcher" to fetcher)
+        every { applicationContextMock.getBeansWithAnnotation(DgsScalar::class.java) } returns emptyMap()
+        every { applicationContextMock.getBeansWithAnnotation(DgsDirective::class.java) } returns emptyMap()
+
+        val provider = DgsSchemaProvider(applicationContextMock, Optional.empty(), Optional.empty(), Optional.empty())
+
+        val build = GraphQL.newGraphQL(provider.schema(schema)).build()
+        val executionResult = build.execute(
+            """{
+            |   khello(input: [FRIENDLY POLITE])
+            |   jhello(input: [FRIENDLY POLITE])
+            |}""".trimMargin()
+        )
+        assertThat(executionResult.errors.isEmpty()).isTrue
+        verify { applicationContextMock.getBeansWithAnnotation(DgsComponent::class.java) }
+    }
+
     @Test
     fun `Kotlin Optional enum @InputArgument with null value`() {
         val schema = """