[ 
https://issues.apache.org/jira/browse/GROOVY-11931?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Eric Milles updated GROOVY-11931:
---------------------------------
    Affects Version/s:     (was: 4.x)

> 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
>            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)

Reply via email to