Подтвердить что ты не робот

Есть ли общая библиотека "backend" для отражения Java?

В настоящее время я работаю со специализированным, интерпретируемым языком программирования, реализованным на Java. В качестве очень небольшой части языка я хотел бы добавить возможность совершать вызовы на Java. Прежде чем я погрузился во все мельчайшие размышления, мне было интересно, знает ли кто-нибудь об общей библиотеке для того, чтобы сделать "backend" часть вызова кода Java рефлексивно.

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

  • Автоматически выбирать правильный метод на основе типов аргументов (например, интеллектуального класса Class.getDeclaredMethod())
  • Разделять дескрипторы между массивами и нормальными объектами
  • и т.д.

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

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

Спасибо!

4b9b3361

Ответ 1

Просто комментарий к собственному ответу; на самом деле beanutils поддерживает получение "близкого соответствия" с учетом набора параметров. См. getMatchingAccessibleMethod()

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

Ответ 2

Попробуйте модуль FEST Reflection. Это простой способ сделать отражение Java. Например:

 String name = method("get").withReturnType(String.class)
                         .withParameterTypes(int.class)
                         .in(names)
                         .invoke(8);

Ответ 5

Если вы ищете простоту, я создал простую библиотеку под названием jOOR, чтобы облегчить доступ к API отражения в Ява. Он поддерживает самые важные действия без создания огромного API. Вот пример того, как выглядит код jOOR:

String world = 
on("java.lang.String") // Like Class.forName()
.create("Hello World") // Call the most specific matching constructor
.call("substring", 6)  // Call the most specific matching substring() method
.call("toString")      // Call toString()
.get()                 // Get the wrapped object, in this case a String

Ответ 6

Я бы сильно подумал и взглянуть на пружины класса ReflectionUtils. Очень мощная обработка отражения.

Ответ 7

Поднять это из мертвых:

invoke(Object object, String methodName, Object[] args) 

Apache Commons lang имеет именно этот метод. MethodUtils # invoke

Ответ 8

Я начал создавать библиотеку com.lexicalscope.fluent-reflection: плавное отражение  который интегрируется с hamcrest и lambdaj

Вы можете написать такой код; который вызывает все аннотированные методы post post в классе:

forEach(
   object(subject).methods(annotatedWith(PostConstruct.class)),
   ReflectedMethod.class).call();

Сообщение в блоге здесь: http://www.lexicalscope.com/blog/category/software-projects/fluent-reflection/

Документация здесь: http://fluent-reflection.lexicalscope.com/

Вы можете получить его от центра maven здесь: http://repo1.maven.org/maven2/com/lexicalscope/fluent-reflection/fluent-reflection/

В настоящее время он имеет некоторые базовые функции, такие как доступ к полям, но он работает для методов. Вероятно, потребуется некоторое время, чтобы добраться до действительно стабильной точки (например, год или два), поскольку я только время от времени работаю над этим. Но он разработан на довольно высоком стандарте качества (надеюсь), и он является open source, поэтому вы можете в основном использовать его, как сейчас, если у него есть все необходимые функции (вам просто придется немного настроить свой код, если хотите для использования новых версий, выпущенных). Я использую его в каком-то производственном коде в тот момент.

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

Ответ 9

Я закончил с предложением Алекс. BeanUtils много помогает для beans, но я не хочу работать только с Beans. FEST выглядит действительно круто, и я добавил его в закладки для дальнейшего изучения, но, как и BeanUtils, он, похоже, не решает, что я считаю сложной проблемой здесь. А именно, учитывая имя метода и список аргументов, выберите метод, который наилучшим образом "подходит" к аргументам. Если метод принимает float и у меня есть double, он должен быть достаточно умным, чтобы не отклонять этот метод, потому что подпись не соответствует точно.

Очевидно, что языки сценариев, построенные на JVM, решают эту проблему, но гораздо сложнее, чем мне нужно из-за специфических для языка оптимизаций. Итак, поскольку это второстепенная и экспериментальная функция, я выбрал быстрое решение, использующее поддержку движка скриптов (в частности, JavaScript) в Java 1.6. Вот основная идея:

private ScriptEngine engine = ... initialize with JavaScript engine ...

private Object invoke(Object object, String methodName, Object[] args) 
   throws RhsFunctionException
{
   // build up "o.method(arg0, arg1, arg2, ...)"
   StringBuilder exp = new StringBuilder("o." + methodName);
   engine.put("o", object);
   buildArgs(arguments, exp);

   try {
      return engine.eval(exp.toString());
   }
   catch (ScriptException e) {
      throw new RhsFunctionException(e.getMessage(), e);
   }
}

private void buildArgs(Object[] args, StringBuilder exp)
{
   // Use bindings to avoid having to escape arguments
   exp.append('(');
   int i = 0;
   for(Symbol arg : args) {
         String argName = "arg" + i;
         engine.put(argName, arg);
         if(i != 0) {
            exp.append(',');
         }
         exp.append(argName);
         ++i;
   }
   exp.append(')');
}

Очевидно, это немного больше, но это основная идея. Мне не нравится создавать строку и оценивать ее, но, используя привязки, предложенные Алексом, я избегаю большинства ошибок, связанных с побегом. Кроме того, у меня есть чистый, простой интерфейс, который я могу заменить с "реальной" реализацией, если это окажется необходимым.

Любая обратная связь или альтернативные решения более чем приветствуются.