Проверить тип возвращаемого значения и параметры отраженного метода в Java

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

Я пытаюсь проверить, что полученный мной обратный вызов указывает на действительный метод. Мне нужно, чтобы присвоение типа возвращаемого значения было совместимо с 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 <Double>.

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

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 (), чтобы получить двойной, который я хочу).

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
2 526
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

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

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

Обновлено:

Вы говорите, что хотите предоставить один класс для типа функции с любым количеством аргументов. Этот может должен быть выполнен с помощью системы типов 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, библиотеку, в которой уже есть много всего этого. Я уверен, что есть еще один, который использует отражение, поэтому вам не нужно писать его самостоятельно.

Отчасти потому, что это открыто регистрируемые обратные вызовы, и я не хочу создавать интерфейс для 1 параметра, 2 параметров и т. д., Возможно, до 10. А также во многом потому, что они также будут иметь примитивные результаты. Единый интерфейс не может уловить эту суть.

Lawrence Dol 04.01.2009 06:27

Кроме того, потому что я хочу, чтобы один класс мог предоставлять обратные вызовы для любого количества методов, а не заставлять каждый вызываемый метод находиться в отдельном классе (и, пожалуйста, не говорите, что я должен использовать анонимные классы).

Lawrence Dol 04.01.2009 06:28

Единый интерфейс может отражает эту суть, но вы можете найти его слишком громоздким. См. Последнее изменение. Что не так с анонимными классами?

Apocalisp 04.01.2009 07:07

Нет, я вообще не об этом спрашиваю. Я хочу подтвердить, что метод при вызове вызова возвращает объект типа Number (из которого я могу вызвать obj.doubleValue (), чтобы получить желаемое значение double).

Lawrence Dol 04.01.2009 07:52

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

Ответ принят как подходящий

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

Другие вопросы по теме