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

Eric Milles resolved GROOVY-11782.
----------------------------------
    Fix Version/s: 5.0.2
       Resolution: Fixed

https://github.com/apache/groovy/commit/7ca25f615fc8e32100ac5ced34e3963d0042ec60

> Inconsistent unboxing of null, and resulting exceptions
> -------------------------------------------------------
>
>                 Key: GROOVY-11782
>                 URL: https://issues.apache.org/jira/browse/GROOVY-11782
>             Project: Groovy
>          Issue Type: Bug
>         Environment: JDK21
> Groovy 4.0.26
>            Reporter: Val E
>            Assignee: Eric Milles
>            Priority: Minor
>             Fix For: 5.0.2
>
>
> So I ran into a weird optimization bug, where an expected exception gets 
> thrown once for an incorrect invocation, will then produce 0 for the exact 
> same incorrect invocations, if its followed by a 'correct' invocation. 
>  
> Attached is a super basic pure java class, with a very basic arithmetic method
> {code:java}
> package test;
> public class JavaTarget {
>     public static double primitiveMethod(double value) {
>         System.out.println("\tJavaTarget.primitiveMethod v="+value);
>         return value - 3.0;
>     }
> }{code}
> The innards of the class are not important, but do note that is take a 
> primitive double param and returns a primitive double after subtracting 3 
> from the param
> Now when groovy tries to call this class, from a closure, with a Double 
> param, we generally expect type coercion, boxing and unboxng, to kick in and 
> everything should still work, and it does under normal circumstances. 
> However the bug occurs when you call with a Double v= null param, in which 
> case type coercion fails, because we cant unbox a null to a double, as 
> expected. If you then call it with a good Double, ex Double v=2.0; all 
> subsequent calls with Double v=null will be coerced to 0 and no more 
> exception will be thrown.
> Test groovy script to illustrate; again vary basic loop 3 times, call java 
> target with null and with a 2.0
> {code:java}
> Closure javaTargetCaller = {Double v ->
>     println "\tcall JavaTarget.primitiveMethod($v)"
>     JavaTarget.primitiveMethod(v)
> }
> for(int i = 0; i<3; i++){
>     try{
>         println "CALL[$i] | with null"
>         Object a = javaTargetCaller(null)
>         println "\tresult with v=null | *NOT-OK* | expecting exception, got 
> "+a+" --"+a.getClass()
>     }catch(Exception x){
>         println "\tresult with v=null| *OK* |expecting exception, got 
> exception --\n"+x
>     }
>     println "CALL[$i] | with v=-2"
>     Object b = javaTargetCaller(-2)
>     println "\tresult with v=-2: expecting -5.0 : got "+b
>     assert b==-5
> }{code}
> You will note the first iteration the call will produce an exception as 
> expected, however the next call with a param of -2, will cache something in 
> the dynamic resolution, and all subsequent calls produce a number, 
> {panel:title=Output}
> CALL[0] | with null
>   call JavaTarget.primitiveMethod(null)
>   result with v=null| *OK* |expecting exception, got exception –
>   groovy.lang.MissingMethodException: No signature of method: static 
> test.JavaTarget.primitiveMethod() is applicable for argument types: (null) 
> values: [null]
> Possible solutions: primitiveMethod(double)
> CALL[0] | with v=-2
>   call JavaTarget.primitiveMethod(-2.0)
>   JavaTarget.primitiveMethod v=-2.0
>   result with v=-2: expecting -5.0 : got -5.0
> CALL[1] | with null
>   call JavaTarget.primitiveMethod(null)
>   JavaTarget.primitiveMethod v=0.0
>   result with v=null | *NOT-OK* | expecting exception, got -3.0 --class 
> java.lang.Double
> CALL[1] | with v=-2
>   call JavaTarget.primitiveMethod(-2.0)
>   JavaTarget.primitiveMethod v=-2.0
>   result with v=-2: expecting -5.0 : got -5.0
> CALL[2] | with null
>   call JavaTarget.primitiveMethod(null)
>   JavaTarget.primitiveMethod v=0.0
>   result with v=null | *NOT-OK* | expecting exception, got -3.0 --class 
> java.lang.Double
> CALL[2] | with v=-2
>   call JavaTarget.primitiveMethod(-2.0)
>   JavaTarget.primitiveMethod v=-2.0
>   result with v=-2: expecting -5.0 : got -5.0
> {panel}
> -note that the very first call indeed failed to unbox the null and threw an 
> exception, however immediately after the second correct call, the nulls start 
> getting unboxed to 0 and no more exception get thrown.
> -it gets more inconsistent, if you change the order and call with a -2 first, 
> then the nulls start getting unboxed to 0 immediately, and no exception is 
> thrown ever
> Almost like some site call somewhere learns how to unbox a Double null, but 
> it depends on the order in which it will be called.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to