Проверка правильности возвращаемого метода и типов в Java - PullRequest
0 голосов
/ 04 января 2009

У меня есть общий объект Callback, который обеспечивает (примитивную) функцию обратного вызова для Java, в отсутствие замыканий. Объект Callback содержит метод и возвращает параметры и типы возврата для метода через пару методов доступа, которые просто делегируют эквивалентные методы в методе.

Я пытаюсь подтвердить, что предоставленный мне обратный вызов указывает на допустимый метод. Мне нужно, чтобы тип возвращаемого значения был совместим с Number, а все параметры должны быть совместимы с Double. Мой метод проверки выглядит так:

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");
            }
        }
    }

Проблема, с которой я сталкиваюсь, заключается в том, что когда я пытаюсь это сделать, например, Math.abs () выдает исключение для возвращаемого типа следующим образом:

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

Это меня удивило, потому что я ожидал, что примитивы будут просто работать, потому что (а) они отражаются с помощью своих классов-обёрток, и (б) объект Double.TYPE объявлен с типом Class .

Кто-нибудь знает, как я могу добиться этого, не изменяя свои проверки на:

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

Разъяснение

Когда вы вызываете метод double abs(double) с помощью Method.invoke (), вы передаете Object [] {Double} и возвращаете Double. Однако моя проверка, похоже, не удалась, потому что Double.TYPE не может быть назначен Double. Поскольку я требую, чтобы все эти обратные вызовы возвращали какой-то номер, который будет возвращен invoke () как Number, я пытаюсь проверить, что предоставленный метод возвращает либо Number, либо числовой примитив.

Проверка паролей аналогична.

Другими словами, при использовании отражения типы parm и return Double и double идентичны, и я хотел бы проверить их легко как таковые.

РЕДАКТИРОВАТЬ: Для дальнейшего уточнения: я хочу проверить, что при вызове invoke () метод будет возвращать объект типа Number (из которого я могу вызвать obj.doubleValue (), чтобы получить желаемое значение double).

Ответы [ 3 ]

1 голос
/ 04 января 2009

Если присмотреться более подробно к документации для Class.isAssignableFrom (), в ней конкретно говорится, что типы примитива не соответствуют ни одному классу, кроме них самих. Поэтому мне нужно будет специально проверить на == равенство Byte.TYPE, Double.TYPE, Float.TYPE, Integer.TYPE, Long.TYPE и Short.TYPE для возвращаемого типа.

1 голос
/ 04 января 2009

Почему бы не сделать это компилятором?

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

Затем вы можете передать F<Double, Double> методу, который ожидает F<? extends Number, ? extends Number>.

EDIT:

Вы говорите, что хотите предоставить один класс для типа функции с любым количеством аргументов. Это можно сделать с помощью системы типов Java. Концептуально каждая функция имеет только один аргумент. Функция с двумя аргументами эквивалентна функции, которая возвращает другую функцию. Итак, вот переменная, значением которой является функция, которая принимает два двойных числа:

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

Вот метод, который передает две двойные для данной функции:

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

Или рассмотрим тип L<A extends L> с двумя подклассами C<E, T extends L<T>>, представляющими «минусы», и тип терминатора 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);
   }  
 }  

}  

В таком случае вы можете реализовать тип функции таким образом:

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

Следующий метод ожидает функцию с двумя Double аргументами (и возвращает Double) вместе с двумя double с, чтобы применить ее к:

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

Реализация интерфейса F должна была бы получить аргументы из списка, используя head и tail. По сути, вы реализуете LISP в Java. :)

Сказав это, посмотрите Функциональная Java , которая является библиотекой, в которой уже есть много этого. Я уверен, что есть еще один, который использует отражение, так что вам не нужно писать это самостоятельно.

0 голосов
/ 04 января 2009

Параметр Math.abs () является двойным примитивом. Я не совсем уверен, что вы подразумеваете под примитивом «совместимость по присваиванию» с объектом (что по сути означает «API-интерфейс отражения» - «может быть приведен»). Но если вы имеете в виду «может перейти в конструктор Double», то это, по сути, простой примитив double (или строка) !! Возможно, вам нужно немного уточнить, что вам нужно делать?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...