2011-05-16 3 views
15

Я работаю над динамическим вызовом кода через интерпретатор, и я попадаю в липкие уродливые области разрешения метода, как описано в JLS section 15.12.Java: разрешение метода выполнения

«Простой» способ выбора метода - это когда вы знаете точные типы всех аргументов, после чего вы можете использовать Class.getDeclaredMethod(String name, Class[] parameterTypes). Возможно, вам нужно проверить доступность метода и суперклассы класса/суперинтерфейсы.

Но это не распространяется на любом из следующих случаев, так что это своего рода бесполезно:

  • бокса/распаковка примитивов
  • подтипы
  • переменной длиной
  • нулевого аргумента (который может быть любой тип, если интерпретатор не знает иначе: во время компиляции любая неоднозначность будет устранена путем исключения null в класс/интерфейс)
  • преобразование примитивного типа (не является частью Java, но допускается в контекст языков - например. Rhino Javascript, где все числа с плавающей точкой, так что код Java может занять int, но вызывающий абонент переходит в номере, который является либо int или double)

(см ниже для быстрого примера первых три)

Так что теперь я должен написать свою собственную библиотеку разрешения метода ...

есть ли хорошо известные рамки библиотека, чтобы помочь в этом?

package com.example.test.reflect; 

import java.lang.reflect.Method; 

public class MethodResolutionTest { 
    public void compute(int i)    { /* implementation... */ } 
    public void compute(Long l)    { /* implementation... */ } 
    public void compute(Object obj)   { /* implementation... */ } 
    public void compute(String... strings) { /* implementation... */ } 

    public static void main(String[] args) { 
     Class<?> cl = MethodResolutionTest.class; 

     /* these succeed */ 
     findAndPrintMethod(cl, "compute", int.class); 
     findAndPrintMethod(cl, "compute", Long.class); 
     findAndPrintMethod(cl, "compute", Object.class); 
     findAndPrintMethod(cl, "compute", String[].class); 

     /* these fail */ 
     findAndPrintMethod(cl, "compute", Integer.class); 
     findAndPrintMethod(cl, "compute", long.class); 
     findAndPrintMethod(cl, "compute", MethodResolutionTest.class); 
     findAndPrintMethod(cl, "compute", String.class, String.class); 
    } 
    private static void findAndPrintMethod(Class<?> objectClass, 
      String methodName, Class<?>... parameterTypes) 
    { 
     try { 
      Method method = findMethod(objectClass, methodName, 
        parameterTypes); 
      System.out.println(method.toString()); 
     } 
     catch (SecurityException e) { 
      e.printStackTrace(); 
     } 
     catch (NoSuchMethodException e) { 
      e.printStackTrace(); 
     } 
    } 
    private static Method findMethod(Class<?> objectClass, 
      String methodName, Class<?>[] parameterTypes) 
     throws SecurityException, NoSuchMethodException 
    { 
     return objectClass.getDeclaredMethod(methodName, parameterTypes); 
    } 
} 
+1

[Этот ответ обрабатывает некоторые ваши случаи, такие как подтипы] (http://stackoverflow.com/questions/2580665/java-getmethod-with-superclass-parameters-in-method/2580699#2580699). –

+1

@Jonathon: Я знаю о isAssignableFrom. У меня есть что-то домашнее, работающее с подтипами и боксом/распаковкой. Затем я начал с варгаров, и это стало неприятно, и я подумал: «Подожди, почему я вообще это делаю?» поэтому я специально ищу существующую библиотеку. (Или, по крайней мере, хороший набор ранее существовавших тестов). В противном случае я могу сделать это самостоятельно, но это большая боль. –

+1

Если вы не найдете сладкую библиотеку, я думаю, что все, что вы делаете, будет уродливым и трудным для чтения. –

ответ

-1

Я имел некоторый успех с MVEL и свойствами, но я не могу вспомнить, может ли он послать вызовы методов.

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

+0

Хмм, я «застрял» с Java по разным причинам, самый большой из которых - ремонтопригодность (добавление другого языка значительно ограничивает мою способность получать помощь от других разработчиков) –

2

Commons BeanUtils имеет эту функцию для нахождения сопоставительных метод: getMatchingAccessibleMethod

Он работает с примитивными типами, но это несколько индетерминисти- как говорит Docs.

+1

Обратите внимание, что в 'getMatchingAccessibleMethod' примитивное сопоставление является одним из способов - Параметр 'Long.class' будет соответствовать' foo (long) ', но' Long.TYPE' не будет соответствовать 'foo (Long)' – McDowell

+0

+1: @Brt: какое облегчение найти Apache получил некоторые инструменты, возможно, не что я хотел, но что-то хотя бы. –

3

Возможно, вы захотите прочитать this blog post и зарегистрируйтесь ClassMate. Он должен сделать для вас большую часть шероховатой работы.

+0

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

0

Один из пользователей на обсуждении guava-discuss Рекомендую посмотреть на Mirror library.

К сожалению, он не обрабатывает перегрузочное разрешение, по крайней мере, в настоящее время.

Смежные вопросы