Skip to content

ToolMethodInvoker loses generic type information for List<T> parameters #677

@richuV

Description

@richuV

Description

When a tool method has a parameter with a generic type like List<MyClass>, the ToolMethodInvoker.convertSingleParameter method fails to properly deserialize it, resulting in a ClassCastException:

java.util.LinkedHashMap cannot be cast to class MyClass
(java.util.LinkedHashMap is in module java.base of loader 'bootstrap';
MyClass is in unnamed module of loader 'app')

Root Cause

In ToolMethodInvoker.java line 298:

Class<?> paramType = parameter.getType();

This only returns the raw type (List.class) and loses the generic type argument (<MyClass>).

When Jackson's convertValue(value, List.class) is called, it doesn't know the element type and defaults to LinkedHashMap.

Reproduction

public class MyTool {
    @Tool(name = my_tool, description = ...)
    public ToolResultBlock doSomething(
            @ToolParam(name = items) List<MyItem> items) {
        // ClassCastException when iterating items
        for (MyItem item : items) { ... }
    }
}

Suggested Fix

Use parameter.getParameterizedType() instead of parameter.getType() to preserve generic type information:

private Object convertSingleParameter(Parameter parameter, Map<String, Object> input) {
    // ... existing code ...

    Type paramType = parameter.getParameterizedType();  // Changed from getType()

    // Handle generic types
    if (paramType instanceof ParameterizedType) {
        JavaType javaType = mapper.getTypeFactory().constructType(paramType);
        return mapper.convertValue(value, javaType);
    }

    // Fallback for non-generic types
    return JsonUtils.getJsonCodec().convertValue(value, parameter.getType());
}

Alternatively, add a new method to JsonCodec interface:

<T> T convertValue(Object from, Type type);

Workaround

Currently, users can work around this by:

  1. Using Object as parameter type and manually converting with TypeReference
  2. Creating a wrapper class instead of using List<T> directly

Environment

  • agentscope-java version: latest main branch
  • Java version: 21

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions