Java: разрешение метода выполнения

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

"Легкий" способ выбора метода - это когда вы знаете точные типы всех аргументов, после чего вы можете использовать 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

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

Ответ 2

Commons beanutils имеют эту функцию для поиска совпадающих методов: getMatchingAccessibleMethod

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

Ответ 3

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

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

Ответ 4

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

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