[Mondrian] Failed to load user-defined function ... does not implement the required interface 'mondrian.spi.UserDefinedFunction'

Julian Hyde jhyde at pentaho.com
Mon Jul 20 14:23:08 EDT 2009


Update. I just checked the code, and we have a test for this exact case.
UdfTest.getGenericFun. I recall that there was a bug about mondrian not
recognizing and using a constructor that takes a string argument.

I don't recall the bug number or change number, and I'm offline right now,
but the fix was made post 3.1.1. Pick up the nightly build and see whether
it fixes your problem. I think it will.

Julian

> -----Original Message-----
> From: mondrian-bounces at pentaho.org 
> [mailto:mondrian-bounces at pentaho.org] On Behalf Of Franco Graziosi
> Sent: Monday, July 20, 2009 1:56 AM
> To: Mondrian developer mailing list
> Subject: [Mondrian] Failed to load user-defined function ... 
> does not implement the required interface 
> 'mondrian.spi.UserDefinedFunction'
> 
> Hello,
> 
> H have created a simple user defined function to simplify zero-divide
> prevention instead of using each time an iif wrapper. The 
> function takes
> two arguments and if the second - denominator - is zero or null
> it returns null.  That function alone works fine. I created a variant
> called "increase" that computes an increase instead of ratio and,
> following Mondrian documentation, I tried to put both function in same
> class varying the defined name. (I actually did the reverse 
> and not working
> went back to define a single function and discovered the cause of the 
> problem).
> 
> Here is the class that implement both functions:
> 
>         package net.cbsolution.ps.pisa.fns;
> 
>         import mondrian.olap.Evaluator;
>         import mondrian.olap.Syntax;
>         import mondrian.olap.type.NumericType;
>         import mondrian.olap.type.Type;
>         import mondrian.spi.UserDefinedFunction;
> 
>         public class Ratio implements UserDefinedFunction {
>           private boolean isIncrease;
>          
>           public Ratio(String name) {
>             if ("Ratio".equals(name))
>               isIncrease = false;
>             else if ("Increase".equals(name))
>               isIncrease = true;
>           }
> 
>           @Override
>           public Object execute(Evaluator evaluator, 
> Argument[] arguments) {
>             final Object arg0 = 
> arguments[0].evaluateScalar(evaluator);
>             final Object arg1 = 
> arguments[1].evaluateScalar(evaluator);
>             if (arg0 == null || arg1 == null || (!(arg0 instanceof
>         Number))  || (!(arg1 instanceof Number)))
>               return null;
>             double denom = ((Number)arg1).doubleValue();
>             if (denom == 0)
>               return null;
>             double result = ((Number)arg0).doubleValue() / denom;
>             if (isIncrease)
>               result -= 1.0;
>             return result;
>           }
> 
>           @Override
>           public String getDescription() {
>             return "Return a ratio between two numbers, prevent zero
>         divide and null values returning null in such cases";
>           }
> 
>           @Override
>           public String getName() {
>             if (isIncrease)
>               return "Increase";
>             else
>               return "Ratio";
>           }
> 
>           @Override
>           public Type[] getParameterTypes() {
>             return new Type[] { new NumericType(), new 
> NumericType() };
>           }
> 
>           @Override
>           public String[] getReservedWords() {
>             return null;
>           }
> 
>           @Override
>           public Type getReturnType(Type[] parameterTypes) {
>             return new NumericType();
>           }
> 
>           @Override
>           public Syntax getSyntax() {
>             return Syntax.Function;
>           }
> 
>         }
> 
> 
> And here is the schema code:
> 
>     <UserDefinedFunction name="Ratio" 
> class="net.cbsolution.ps.pisa.fns.Ratio" />
>     <UserDefinedFunction name="Increase" 
> class="net.cbsolution.ps.pisa.fns.Ratio" />
> 
> I get the following exception:
> 
>     Mondrian Error:Failed to load user-defined function '': class 
> 'net.cbsolution.ps.pisa.fns.Ratio' does not implement the required 
> interface 'mondrian.spi.UserDefinedFunction'
> 
> Looking at stack trace I went to the problem 
> (mondrian.olap.Util : 2280):
> 
>        try {
>             udf = (UserDefinedFunction) udfClass.newInstance();
>         } catch (InstantiationException e) {
>             throw 
> MondrianResource.instance().UdfClassWrongIface.ex("",
>                     className, UserDefinedFunction.class.getName());
>         } catch (IllegalAccessException e) {
>             throw 
> MondrianResource.instance().UdfClassWrongIface.ex("",
>                     className, UserDefinedFunction.class.getName());
> 
> Mondrian code tries to instantiate with a zero-argument 
> constructor that 
> obviously do
> not exists. (Note: if I define a zero argument constructor 
> the function 
> is instantiated but
> I get a duplicate Ratio and no Increase).
> 
> Are multiple-name functions really supported?
> 
> fg
> 
> 
> _______________________________________________
> Mondrian mailing list
> Mondrian at pentaho.org
> http://lists.pentaho.org/mailman/listinfo/mondrian
> 
> 
> 





More information about the Mondrian mailing list