From bc32948b462e8cc17c366c661f29564aade5c93e Mon Sep 17 00:00:00 2001 From: James Jiang Date: Sun, 21 Jun 2026 00:30:45 +1000 Subject: [PATCH] fix: widen Integer to Long in castValue() for boxed Long parameter --- .../com/google/adk/tools/FunctionTool.java | 5 ++- .../google/adk/tools/FunctionToolTest.java | 33 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/google/adk/tools/FunctionTool.java b/core/src/main/java/com/google/adk/tools/FunctionTool.java index d802fad63..91abb10e2 100644 --- a/core/src/main/java/com/google/adk/tools/FunctionTool.java +++ b/core/src/main/java/com/google/adk/tools/FunctionTool.java @@ -450,9 +450,12 @@ private Object castValue(Object value, Class type) { } } if (type.equals(Long.class) || type.equals(long.class)) { - if (value instanceof Long || value instanceof Integer) { + if (value instanceof Long) { return value; } + if (value instanceof Integer i) { + return i.longValue(); + } } else if (type.equals(Double.class) || type.equals(double.class)) { if (value instanceof Double d) { return d.doubleValue(); diff --git a/core/src/test/java/com/google/adk/tools/FunctionToolTest.java b/core/src/test/java/com/google/adk/tools/FunctionToolTest.java index 24ad7e618..d68a9b6d7 100644 --- a/core/src/test/java/com/google/adk/tools/FunctionToolTest.java +++ b/core/src/test/java/com/google/adk/tools/FunctionToolTest.java @@ -299,6 +299,31 @@ public void call_withAllSupportedParameterTypes() throws Exception { .buildOrThrow()); } + @Test + public void call_withPrimitiveLongParam_whenModelProvidesInteger_succeeds() throws Exception { + // When the model returns a small integer (e.g. 42), Jackson deserializes it as Integer. + // Primitive long was never broken — Java reflection auto-widens int to long. + FunctionTool tool = FunctionTool.create(Functions.class, "echoPrimitiveLong"); + + Map result = + tool.runAsync(ImmutableMap.of("value", Integer.valueOf(42)), toolContext).blockingGet(); + + assertThat(result).containsExactly("value", 42L); + } + + @Test + public void call_withBoxedLongParam_whenModelProvidesInteger_succeeds() throws Exception { + // When the model returns a small integer (e.g. 42), Jackson deserializes it as Integer. + // Boxed Long was broken before the fix — castValue() returned the raw Integer, causing + // reflection to throw IllegalArgumentException (Integer is not assignable to Long). + FunctionTool tool = FunctionTool.create(Functions.class, "echoBoxedLong"); + + Map result = + tool.runAsync(ImmutableMap.of("value", Integer.valueOf(42)), toolContext).blockingGet(); + + assertThat(result).containsExactly("value", 42L); + } + @Test public void create_withPojoParamWithFields() { FunctionTool tool = FunctionTool.create(Functions.class, "pojoParamWithFields"); @@ -1064,6 +1089,14 @@ public static ImmutableMap returnAllSupportedParametersAsMap( .buildOrThrow(); } + public static ImmutableMap echoPrimitiveLong(long value) { + return ImmutableMap.of("value", value); + } + + public static ImmutableMap echoBoxedLong(Long value) { + return ImmutableMap.of("value", value); + } + public static ImmutableMap returnsParameterizedList( List> listParam, ToolContext toolContext) { return ImmutableMap.builder().put("listParam", listParam).buildOrThrow();