Есть ли общая "бэкэнд" библиотека для отражения Java - PullRequest
11 голосов
/ 13 декабря 2008

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

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

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

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

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

Спасибо!

Ответы [ 10 ]

7 голосов
/ 15 декабря 2008

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

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

7 голосов
/ 14 декабря 2008

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

 String name = method("get").withReturnType(String.class)
                         .withParameterTypes(int.class)
                         .in(names)
                         .invoke(8);
3 голосов
/ 29 декабря 2011

Если вы ищете простоту, я создал простую библиотеку под названием jOOR , чтобы облегчить доступ к API отражения в Java. Он поддерживает самые важные действия без создания огромного 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
2 голосов
/ 13 декабря 2008

Посмотрите на Apache Commons BeanUtils

2 голосов
/ 13 декабря 2008

Взгляните на Поддержка сценариев Java ; Я верю, что это поможет вам решить вашу проблему.

1 голос
/ 21 декабря 2011

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

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

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 Central здесь: http://repo1.maven.org/maven2/com/lexicalscope/fluent-reflection/fluent-reflection/

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

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

1 голос
/ 03 июня 2010

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

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

Apache Commons lang использует именно этот метод. MethodUtils # взывать

1 голос
/ 21 января 2010

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

0 голосов
/ 07 ноября 2011

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

https://github.com/yclian/Reflects.java/blob/master/src/test/java/my/jug/reflects/ReflectsTest.java

Это вдохновлено Guava, так что вы можете использовать Predicate для фильтрации методов, которые вам нравятся.

0 голосов
/ 14 декабря 2008

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

Очевидно, что языки сценариев, построенные на 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(')');
}

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

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

...