Какое-либо решение для Class.getMethod () отражение и автоупаковка?

Простая фиксация: Присоедините случайную строку запроса к изображению:

<img src="foo.cgi?random=323527528432525.24234" alt="">

, Что говорит RFC HTTP:

Cache-Control: no-cache

, Но это не работает что хорошо:)

17
задан Daff 12 December 2009 в 22:03
поделиться

6 ответов

Как упоминает @Stephen C, ваша единственная надежда - провести поиск самостоятельно. Все его предостережения остаются в силе, но я бы сказал, что небольшая гибкость будет иметь большое значение для покрытия большинства ошибок, если звонящие будут осведомлены о предостережениях ... вместо того, чтобы заставлять ваших звонящих всегда быть болезненно конкретными.

Для код, который действительно делает что-то вроде этого, вы можете посмотреть здесь: http://meta-jb.svn.sourceforge.net/viewvc/meta-jb/trunk/dev/src/main/java/org/progeeks/util/MethodIndex.java?revision=3811&view=markup

Вызов findMethod () является точкой входа, но делегирует (после некоторого кэширования и т. Д.) Этому методу:

private Method searchForMethod( String name, Class[] parms ) {
    Method[] methods = type.getMethods();
    for( int i = 0; i < methods.length; i++ ) {
        // Has to be named the same of course.
        if( !methods[i].getName().equals( name ) )
            continue;

        Class[] types = methods[i].getParameterTypes();

        // Does it have the same number of arguments that we're looking for.
        if( types.length != parms.length )
            continue;

        // Check for type compatibility
        if( InspectionUtils.areTypesCompatible( types, parms ) )
            return methods[i];
        }
    return null;
}

InspectionUtils.areTypesCompatible () принимает два списка типов, нормализует их примитивы, а затем проверяет, что один из них равен назначается "другому. Таким образом, он будет обрабатывать случай, когда у вас есть Integer и вы пытаетесь вызвать метод, который принимает int, а также случай, когда у вас есть String и вы пытаетесь вызвать метод, который принимает Object. Он не обрабатывает случай наличия int и вызова метода, который принимает float. Должна быть некоторая специфичность.

Единственное предостережение заключается в том, что вышеупомянутый метод просто выполняет поиск в порядке, поэтому, если есть неоднозначности, выбор будет произвольным. На практике я никогда не сталкивался с реальными проблемами.

Вот проверка совместимости для справки: общедоступное статическое логическое значение areTypesCompatible (цели класса [], источники класса []) { если (targets.length! = sources.length) return false;

    for( int i = 0; i < targets.length; i++ ) {
        if( sources[i] == null )
            continue;

        if( !translateFromPrimitive( targets[i] ).isAssignableFrom( sources[i] ) )
            return false;
        }
    return( true );
}

Код принадлежит мне и BSD, поэтому использование фрагментов разрешено. Если вы решите, что предпочтете использовать этот пакет утилит напрямую, самый последний общедоступный выпуск находится здесь: https://meta-jb.svn.sourceforge.net/svnroot/meta-jb/trunk/dev/m2-repo/org/meta-jb/meta-jb-util/0.17.1/

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

11
ответ дан 30 November 2019 в 12:36
поделиться

Yeah you need to use Integer.TYPE or (equivalently) int.class.

Update: "My parameterTypes array comes from somewhere and I know that it will only return non primitive types." Well, then that's this "somewhere"'s problem. If they don't give you the proper signature of the method they want, then how are you going to find it? What if there are two overloaded methods, that differ only in one of them takes a primitive and the other one takes the wrapper class? Which one does it choose then? I mean, if you really have no choice then I guess you could just loop through all the methods, and look for one with the right name, and manually check all the parameter types for whether they are correct, or are the primitive equivalents.

4
ответ дан 30 November 2019 в 12:36
поделиться

Integer.class represents the Integer object type. Integer.TYPE represents the int primitive type. Does that work?

2
ответ дан 30 November 2019 в 12:36
поделиться

поиск метода отражения не так сложен, как метод компилятора. Я понимаю, зачем тебе что-то подобное. предположим, что во время выполнения у вас есть имя метода и массив объектов в качестве аргументов, и вы хотите, чтобы отражение давало вам точный метод, основанный на типах аргументов, но это более сложно. например:

void f(Integer i){..}
void f(int i){...}

, когда аргумент имеет тип Integer, какой из них вы можете выбрать? Еще более хитрый:

void f(Integer i, List l){...}
void f(Object o, LinkedList l){...}

компилятор имеет набор правил для выбора «наиболее конкретного метода» на основе статической информации; если он не может определить, он сразу же предупредит вас.

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

2
ответ дан 30 November 2019 в 12:36
поделиться

The only answer at the moment is to write code to simulate the Java compiler's type promotion rules, an reflectively pick the most appropriate method. Autoboxing and unboxing are just examples of the type promotions the compiler knows about ...

Why don't the Java reflective APIs already do this? I can think of a number of reasons.

  • Before Java 1.5, the getMethod class and friends did not understand how to do (for example) promotion of int to float. If there wasn't a need pre-1.5, why now?

  • Adding this kind of stuff will make reflective method calling even slower.

  • Autoboxing and unboxing can be confusing with non-reflective method invocation. Adding reflection will only add more confusion.

  • The runtime implementation of the promotion rules will add a class of new runtime error cases that need to be mapped to exceptions and diagnosed by user code. These ones will be particularly tricky. For example, it would have to deal with the reflective equivalent of an ambiguous method call.

  • The overarching requirement for backwards compatibility means that Sun would have to implement this as new methods. They cannot change the behaviors of the current methods because that would potentially break thousands of customers' existing applications.

There is one final point that relates specifically to the OP's use-case (as described). The OP says that his code does not know whether to expect (for example) a method with an int or Integer parameter on the target class. Suppose that the person who wrote the target class provided both overloads ... and the semantics are subtly (or unsubtly) different? No matter what you do, there will be situations where the OP's code picks the overload that the client doesn't expect. Bad.

IMO, it is better for the OP's code to impose some simple API rules that say when it is correct to use primitives versus wrappers.

1
ответ дан 30 November 2019 в 12:36
поделиться

Вы можете добавить некоторую дополнительную логику вокруг вызова отражения, которая пытается преобразовать ваш Integer.class (или что-либо еще) в соответствующий примитивный класс, а затем многократно искать метод, пока вы не получите совпадение. Если у вас есть Apache Commons Lang, то метод wrapperToPrimitive сделает этот разговор за вас, но написание его само по себе тривиально.

  1. Выполните getMethod как обычно
  2. Если ничего не найдено, то ищите любые типы параметров, которые имеют соответствующие примитивы
  3. Для каждой их комбинации выполняйте другой поиск до тех пор, пока что-нибудь не застрянет.

Не элегантно, а для методов с большим количеством примитивных параметров это может быть даже медленно.

.
0
ответ дан 30 November 2019 в 12:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: