[
https://issues.apache.org/jira/browse/GROOVY-11931?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Eric Milles updated GROOVY-11931:
---------------------------------
Language: groovy
> Incorrect method resolution precedence for overloaded methods with Map
> parameter
> --------------------------------------------------------------------------------
>
> Key: GROOVY-11931
> URL: https://issues.apache.org/jira/browse/GROOVY-11931
> Project: Groovy
> Issue Type: Bug
> Affects Versions: 4.x
> Reporter: Gianluca Sartori
> Assignee: Eric Milles
> Priority: Major
>
> Groovy incorrectly resolves overloaded methods when one overload accepts a
> {{Map}} and another accepts a {{{}Serializable{}}}. Because {{Map}}
> implements {{{}Serializable{}}}, the runtime method selection prefers the
> {{Serializable}} overload even when a {{Map}} is explicitly provided as a
> named argument.
> This leads to unintended method dispatch, recursive invocation, and
> ultimately a {{{}StackOverflowError{}}}.
> h2. Steps to Reproduce
>
> {{def get(Serializable id) {}}
> {{ return get(id: id)}}
> {{}}}
> {{def get(Map filterParams) {}}
> {{ return buildQuery(filterParams).get()}}
> {{}}}
>
> Invocation:
>
> {{get(Map.of("k1", "id", "v1", 1))}}
>
> h2. Actual Behavior
> * Groovy selects {{get(Serializable id)}} instead of {{get(Map
> filterParams)}}
> * The selected method interprets the named argument as a recursive call
> * This results in infinite recursion
> * Eventually throws {{StackOverflowError}}
> h2. Expected Behavior
> * When a {{Map}} is explicitly passed, Groovy should select {{get(Map
> filterParams)}}
> * Method resolution should prefer the most specific compatible type
> ({{{}Map{}}}) over a broader supertype ({{{}Serializable{}}})
> * Behavior should align with developer intent and Java-like overload
> resolution expectations
> h2. Impact
> * Unintended infinite recursion in valid and common overload patterns
> * Hard-to-diagnose runtime failures ({{{}StackOverflowError{}}})
> * Makes {{{}Map{}}}-based overloads unsafe when any other overload accepts a
> supertype such as {{{}Serializable{}}}, {{{}Object{}}}, etc.
> * Breaks expected polymorphic dispatch semantics for named arguments
> h2. Additional Findings
>
> {{Map m = [:]}}
> {{assert m instanceof Serializable // true}}
>
> Because {{Map}} implements {{{}Serializable{}}}, Groovy’s overload resolution
> prefers the {{Serializable}} overload due to type compatibility, despite a
> more specific {{Map}} signature being available.
> Observed behavior suggests Groovy’s method selection algorithm prioritizes
> assignability to broader supertypes rather than specificity of declared
> parameter type in certain multi-method resolution paths.
> Using {{LinkedHashMap}} or different concrete types may alter resolution
> outcomes, indicating inconsistency in dispatch behavior.
> h2. Environment
> * Groovy 4.x
> h2. Notes
> *This behavior deviates from intuitive overload resolution rules and differs
> from Java’s method selection strategy. It introduces a subtle and high-risk
> edge case in APIs that expose both {{Map}} and {{Serializable}} (or other
> supertype) overloads.*
--
This message was sent by Atlassian Jira
(v8.20.10#820010)