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

Julian Hyde updated CALCITE-1434:
---------------------------------
    Description: 
{{AggregateFunctionImpl}} doesn't work if the class implements a generic 
interface. We have an interface like below which we want to expose to users for 
writing aggregate functions.

{noformat}
public interface UDAF<A, V, R> {
    A init();
    A add(A aggregate, V val);
    R result(A aggregate);
}
{noformat}


Internally we create an instance of {{AggregateFunctionImpl}} and register the 
Function in {{SchemaPlus}}. However this doesn't work for example if we have an 
implementation like below,

{noformat}
public class MySum implements UDAF<Number, Number, Number> {
    @Override
    public Number init() {...}
    @Override
    public Number add(Number aggregate, Number val) {...}
    @Override
    public Number result(Number aggregate) {...}
}
{noformat}

We get an Exception "java.lang.RuntimeException: In user-defined aggregate 
class 'x.y.z.$MySum', first parameter to 'add' method must be the accumulator 
(the return type of the 'init' method)"

This happens because the ReflectiveFunctionBase.findMethod is trying to look 
for a method name "init" and it get a method with a different signature (that 
returns Object) instead of the actual method defined in MySum. This happens to 
be a 'bridge' method inserted by java.

In findMethod, the bridge methods can be skipped while looking for the method 
by name. 

  was:
We have an interface like below which we want to expose to users for writing 
aggregate functions.

{noformat}
public interface UDAF<A, V, R> {
    A init();
    A add(A aggregate, V val);
    R result(A aggregate);
}
{noformat}


Internally we create an instance of AggregateFunctionImpl and register the 
Function in SchemaPlus. However this doesn't work for example if we have an 
implementation like below,

{noformat}
public class MySum implements UDAF<Number, Number, Number> {
    @Override
    public Number init() {...}
    @Override
    public Number add(Number aggregate, Number val) {...}
    @Override
    public Number result(Number aggregate) {...}
}
{noformat}

We get an Exception "java.lang.RuntimeException: In user-defined aggregate 
class 'x.y.z.$MySum', first parameter to 'add' method must be the accumulator 
(the return type of the 'init' method)"

This happens because the ReflectiveFunctionBase.findMethod is trying to look 
for a method name "init" and it get a method with a different signature (that 
returns Object) instead of the actual method defined in MySum. This happens to 
be a 'bridge' method inserted by java.

In findMethod, the bridge methods can be skipped while looking for the method 
by name. 


> User-defined aggregate function that uses a generic interface
> -------------------------------------------------------------
>
>                 Key: CALCITE-1434
>                 URL: https://issues.apache.org/jira/browse/CALCITE-1434
>             Project: Calcite
>          Issue Type: Bug
>            Reporter: Arun Mahadevan
>            Assignee: Julian Hyde
>             Fix For: 1.11.0
>
>
> {{AggregateFunctionImpl}} doesn't work if the class implements a generic 
> interface. We have an interface like below which we want to expose to users 
> for writing aggregate functions.
> {noformat}
> public interface UDAF<A, V, R> {
>     A init();
>     A add(A aggregate, V val);
>     R result(A aggregate);
> }
> {noformat}
> Internally we create an instance of {{AggregateFunctionImpl}} and register 
> the Function in {{SchemaPlus}}. However this doesn't work for example if we 
> have an implementation like below,
> {noformat}
> public class MySum implements UDAF<Number, Number, Number> {
>     @Override
>     public Number init() {...}
>     @Override
>     public Number add(Number aggregate, Number val) {...}
>     @Override
>     public Number result(Number aggregate) {...}
> }
> {noformat}
> We get an Exception "java.lang.RuntimeException: In user-defined aggregate 
> class 'x.y.z.$MySum', first parameter to 'add' method must be the accumulator 
> (the return type of the 'init' method)"
> This happens because the ReflectiveFunctionBase.findMethod is trying to look 
> for a method name "init" and it get a method with a different signature (that 
> returns Object) instead of the actual method defined in MySum. This happens 
> to be a 'bridge' method inserted by java.
> In findMethod, the bridge methods can be skipped while looking for the method 
> by name. 



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to