是否有一个用于Java反射的通用“后端”库

时间:2008-12-13 00:00:07

标签: java reflection dynamic invoke

我目前正在使用Java实现的专业解释编程语言。作为该语言的一小部分,我想添加调用Java的能力。在深入研究反射的所有细节之前,我想知道是否有人知道有一个通用库来执行反向调用Java代码的“后端”部分。

也就是说,我将一个字符串(我定义语法)解析为一些表示Java方法调用(或构造函数或字段访问)的数据结构,然后将该数据结构传递给调用该调用并返回该调用的库。结果。特别是,我希望它已经处理了我不想弄清楚的所有边缘情况:

  • 根据参数类型自动选择正确的方法(如智能Class.getDeclaredMethod())
  • 处理数组与普通对象引用之间的区别

我花了一点时间在JVM上查看动态语言的实现,但这些通常比我正在寻找的要复杂得多,或者针对特定语言进行了高度优化。

另一个选择是将我的语法转换为某种动态语言的字符串,并使用Rhino或其他东西调用它,但这比我正在寻找的开销稍微多一些。

谢谢!

11 个答案:

答案 0 :(得分:7)

尝试FEST Reflection模块。这是一种流畅的Java反射方式。例如:

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

答案 1 :(得分:7)

只是评论你自己的答案;实际上,beanutils支持在给定一组参数的情况下获得“紧密匹配”。见getMatchingAccessibleMethod()

BeanUtils非常强大,并且有很多用于检查类的实用方法。构造函数自然可以获得相同的支持。

答案 2 :(得分:3)

如果您正在寻找简单性,我创建了一个名为jOOR的简单库,以便于在Java中访问反射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

答案 3 :(得分:2)

看看Java's scripting support;我相信它会帮助你解决问题。

答案 4 :(得分:2)

答案 5 :(得分:1)

我强烈考虑看一下SPR的ReflectionUtils类。 非常强大的反射处理。

答案 6 :(得分:1)

从死里复活:

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

Apache Commons lang正是这种方法。 MethodUtils#invoke

答案 7 :(得分:1)

我已经开始创建一个库com.lexicalscope.fluent-reflection:fluent-reflection  它与hamcrestlambdaj

集成在一起

你可以写这样的代码;它调用类中的所有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 central获取它: http://repo1.maven.org/maven2/com/lexicalscope/fluent-reflection/fluent-reflection/

目前缺少一些基本功能,例如访问字段,但它适用于方法。它可能需要一段时间才能达到一个非常稳定的功能点(比如一年或两年),因为我偶尔只会处理它。但是它被开发成相当高质量的标准(我希望)并且它是开源的,所以如果它具有你需要的所有功能,你现在基本上可以使用它(如果你想要你可能需要稍微调整一下你的代码)使用已发布的较新版本)。我现在在一些生产代码中使用它。

它的设计非常易于扩展,因此您可以插入策略,以松散耦合(组合)的方式查找所需的方法。因此,如果它没有您想要的确切方法查找策略,希望可以轻松添加它。

答案 8 :(得分:0)

我最终选择了Alex的建议。 BeanUtils对bean很有帮助,但我不想单独使用Beans。 FEST看起来非常酷,我已将它加入书签以供进一步研究,但是像BeanUtils一样,它似乎并没有解决我认为这里的难题。也就是说,给定方法名称和参数列表,选择最适合参数的方法。如果一个方法采用浮点数并且我有一个双精度数,那么它应该足够聪明,不要拒绝该方法,因为签名不完全匹配。

显然,构建在JVM上的脚本语言解决了这个问题,但由于语言特定的优化,它的方式比我需要的要复杂得多。因此,由于这是一个次要的实验性功能,我选择了使用Java 1.6中的脚本引擎支持(特别是JavaScript)的快速解决方案。这是基本的想法:

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(')');
}

显然还有一点,但这是基本的想法。我真的不喜欢建立一个字符串并对其进行评估,但是通过使用Alex建议的绑定,我避免了大部分的转义陷阱。此外,我有一个干净,简单的界面,如果证明有必要,我可以用“真正的”实现交换。

非常欢迎任何反馈或替代解决方案。

答案 9 :(得分:0)

我在阅读完这个帖子之后编写并开源了这段代码,也许你会发现它很有用。

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

它受到了Guava的启发,因此您可以使用Predicate来过滤您喜欢的方法。

答案 10 :(得分:0)

有一个reflections项目,与上文列出的其他手段相比,我相信该项目具有Java 8支持的最新实用程序反射库,并且最终是进行某些高级反射操作的最佳方法2020年。

它显示为:

发布的org.reflections:reflections:0.9.12-支持Java 8
...
反射库每月从Maven Central下载超过250万次,数千个项目和库都在使用它。我们正在寻找维护人员来协助审核拉动请求和管理发布,请与我们联系。
...
Reflections扫描您的类路径,为元数据建立索引,使您可以在运行时对其进行查询,并可以保存和收集项目中许多模块的信息。

与Java Standard Reflection结合使用,它应该可以满足您的所有需求。