views:

768

answers:

3

I have a generic Callback object which provides a (primitive) callback capability for Java, in the absence of closures. The Callback object contains a Method, and returns the parameter and return types for the method via a couple of accessor methods that just delegate to the equivalent methods in Method.

I am trying to validate that a Callback I have been supplied points to a valid method. I need the return type assignment compatible with Number and all parameters to be assignment compatible with Double. My validating method looks like this:

static public void checkFunctionSpec(Callback cbk) {
    Class[]                             prms=cbk.getParmTypes();
    Class                               ret =cbk.getReturnType();

    if(!Number.class.isAssignableFrom(ret)) {
        throw new IllegalArgumentException(
           "A function callback must return a Number type " + 
           "(any Number object or numeric primitive) - function '" +
           cbk + "' is not permitted");
        }
    for(Class prm: prms) {
        if(!Double.class.isAssignableFrom(prm)) {
            throw new IllegalArgumentException(
               "A function callback must take parameters of " +
               "assignment compatible with double " +
               "(a Double or Float object or a double or float primitive) " +
               "- function '" + cbk + "' is not permitted");
            }
        }
    }

The problem I encounter is that the when I try this with, e.g. Math.abs(), it's throwing an exception for the return type as follows:

java.lang.IllegalArgumentException:
A function callback must return a Number type (any Number object or numeric primitive)
- function 'public static double java.lang.Math.abs(double)' is not permitted

This was surprising to me because I expected primitives to simply work because (a) they are reflected using their wrapper classes, and (b) the Double.TYPE is declared to be of type Class<Double>.

Does anyone know how I can achieve this without modifying my checks to be:

if(!Number.class.isAssignableFrom(ret)
     && ret!=Double.TYPE
     && ret!=Float.TYPE
     && ret!=...) {


Clarification

When you invoke the method double abs(double) using Method.invoke(), you pass in a Object[]{Double} and get back a Double. However, my validation appears to be failing because Double.TYPE is not assignable to a Double. Since I require all these callbacks to return some sort of number, which will be returned by invoke() as a Number, I am trying to validate that the supplied method returns either Number or a numeric primitive.

Validation of the parms is likewise.

In other words, when using reflection the parm and return types Double and double are identical and I would like to validate them easily as such.

EDIT: To further clarify: I want to validate that a Method will, when invoke() is called return an Object of type Number (from which I can call obj.doubleValue() to get the double I want).

+1  A: 

Why not have the compiler do it?

public interface F<A, B> {
   public B $(A a);
}

Then you can pass an F<Double, Double> to a method that expects an F<? extends Number, ? extends Number>.

EDIT:

You say you want to provide a single class for the type of a function with any number of arguments. This can be done with the Java type system. Conceptually every function has only one argument. A function with two arguments is equivalent to a function that returns another function. So here's a variable whose value is a function that takes two doubles:

F<Double, F<Double, Double>> f;

Here's a method that passes two doubles to a given function:

public Double operate(F<Double, F<Double, Double>> f, double a, double b) {
   return f.$(a).$(b);
}

Or, consider a type L<A extends L> with two subclasses C<E, T extends L<T>> representing a "cons", and a terminator type N:

public abstract class L<A extends L<A>> {  
 private L() {}  

 private static final N nil = new N();  

 public static N nil() {  
   return nil;  
 }  

 public static final class N extends L<N> {  
   private N() {}  

   public <E> C<E, N> cons(final E e) {  
     return new C<E, L>(e, this);  
   }  
 }  

 public static final class C<E, L extends L<L>> extends L<C<E, L>> {  
   private E e;  
   private L l;  

   private C(final E e, final L l) {  
     this.e = e;  
     this.l = l;  
   }  

   public E head() {  
     return e;  
   }  

   public L tail() {  
     return l;  
   }  

   public <E> C<E, C<E, L>> cons(final E e) {
     return new C<E, C<E, L>>(e, this);
   }  
 }  

}

In such a case, you can implement a function type thusly:

public interface F<A extends L<A>, B> {
   public B $(A args);
}

The following method expects a function with two Double arguments (and returns a Double), along with two doubles to apply it to:

public Double operate(F<C<Double, C<Double, N>>, Double> f, double a, double b) {
   return f.$(N.nil().cons(b).cons(a));
}

The implementation of the F interface would have to get the arguments from the list using head and tail. So in effect, you're implementing LISP in Java. :)

Having said that, check out Functional Java, which is a library that has a lot of this stuff already. I'm sure there's also one out there that uses reflection so you don't have to write it yourself.

Apocalisp
In part because these are openly registerable callbacks and I don't want to create an interface for 1 parm, 2 parms, and so through to perhaps 10. And also in big part because these will have primitive returns also. A single interface can't capture that essense.
Software Monkey
Also, because I want a single class to be able to provide callbacks for any number of method, and not force each method which is invoked to be in a separate class (and please don't say I should use anonymous classes).
Software Monkey
A single interface _can_ capture that essence, but you may find it overly cumbersome. See the last edit. What's wrong with anonymous classes?
Apocalisp
No, that's not what I am asking at all. I want to validate that a Method will, when invoke is called return an Object of type Number (from which I can call obj.doubleValue() to get the double I want).
Software Monkey
A: 

The parameter to Math.abs() is the double primitive. I'm not quite sure what you mean by a primitive being "assignment compatible" with an object (what the reflection API essentially means is "can be a cast of"). But if you mean "can pass into a Double constructor", then that's essentially a primitive double (or a string)!! Perhaps you need to clarify a bit more what you need to do?

Neil Coffey
+1  A: 

Looking more closely at the documentation for Class.isAssignableFrom(), it specifically states that the types for a primitive do not match any class except themselves. So I will need to specifically check for == equality to Byte.TYPE, Double.TYPE, Float.TYPE, Integer.TYPE, Long.TYPE, and Short.TYPE for the return type.

Software Monkey