From 494e3c6bc886d9bc5ad603dd7b55e4ef7a77eede Mon Sep 17 00:00:00 2001 From: Dan Poineau Date: Fri, 30 May 2025 17:57:54 -0700 Subject: [PATCH 1/2] Fix issue with non-Optional generic parameters in controller methods throwing an exception --- .../main/java/ninja/params/ControllerMethodInvoker.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ninja-core/src/main/java/ninja/params/ControllerMethodInvoker.java b/ninja-core/src/main/java/ninja/params/ControllerMethodInvoker.java index deb5a5e573..327fa9c57e 100644 --- a/ninja-core/src/main/java/ninja/params/ControllerMethodInvoker.java +++ b/ninja-core/src/main/java/ninja/params/ControllerMethodInvoker.java @@ -417,6 +417,13 @@ private MethodParameter(Type genericType) { if (maybeOptional.isAssignableFrom(Optional.class)) { isOptional = true; parameterClass = getClass(parameterizedType.getActualTypeArguments()[0]); + } else { + // This case is necessary here for types like List + // because genericType is not a class in that case, so letting it fall through below throws an exception. + // So we explicitly handle the case here and use parameterizedType.getRawType() as the parameterClass + // (which would be List in the example above), and matches the behavior of older Ninja versions. + isOptional = false; + parameterClass = maybeOptional; } } From e219b885d889fb4b8b0c1e36b6024aed5418c195 Mon Sep 17 00:00:00 2001 From: Dan Poineau Date: Fri, 30 May 2025 18:49:56 -0700 Subject: [PATCH 2/2] Add test --- .../ninja/params/ControllerMethodInvokerTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ninja-core/src/test/java/ninja/params/ControllerMethodInvokerTest.java b/ninja-core/src/test/java/ninja/params/ControllerMethodInvokerTest.java index f944cca626..6aedc97bed 100644 --- a/ninja-core/src/test/java/ninja/params/ControllerMethodInvokerTest.java +++ b/ninja-core/src/test/java/ninja/params/ControllerMethodInvokerTest.java @@ -58,6 +58,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Date; +import java.util.List; import java.util.Optional; import static org.junit.Assert.*; @@ -1073,6 +1074,14 @@ public void bodyWithOptionalShouldBeEmptyIfNoBodyPresent() { verify(mockController).bodyWithOptional(Optional.empty()); } + @Test + public void bodyWithGenericTypeShouldRun() { + List body = Arrays.asList("value1", "value2"); + when(context.parseBody(List.class)).thenReturn(body); + create("bodyWithGenericType").invoke(mockController, context); + verify(mockController).bodyWithGenericType(body); + } + // JSR303Validation(@Pattern(regexp = "[a-z]*") String param1, // @Length(min = 5, max = 10) String param2, @Min(3) @Max(10) int param3); @Test @@ -1426,6 +1435,8 @@ public Result multiple(@Param("param1") String param1, @PathParam("param2") int public Result badValidatorWithOptional(@Param("param1") @NumberValue(min = 10) Optional param1); public Result body(Object body); + + public Result bodyWithGenericType(List myList); public Result bodyWithOptional(Optional body);