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

发布于 2024-07-10 19:22:49 字数 478 浏览 8 评论 0原文

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

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

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

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

另一种选择是将我的语法转换为某种动态语言的字符串,并使用 Rhino 或其他东西调用它,但这比我想要的开销要大一些。

I'm currently working with a specialized, interpreted, programming language implemented in Java. As a very small part of the language, I'd like to add the ability to make calls into Java. Before I dive into all of the nitty-gritty of reflection, I was wondering if anyone knew of a general library for doing the "back-end" part of invoking Java code reflectively.

That is, I parse a string (I define the grammar) into some data structure that represents a Java method call (or constructor, or field access) and then pass that data structure to this library that invokes the call and returns the result. In particular, I'd like it to already handle all the edge cases that I don't want to figure out:

  • Automagically pick the right method based on the types of arguments (like an intelligent Class.getDeclaredMethod())
  • Handle distinction between arrays and normal object references
  • etc

I've spent a little time looking at the implementations of dynamic languages on the JVM, but these are generally much more complicated than I'm looking for, or highly optimized for the particular language.

Another option is to convert my grammar into a string in some dynamic language and invoke it with Rhino or something, but that's a little more overhead than I'm looking for.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

ら栖息 2024-07-17 19:22:49

只是对您自己的答案的评论; 实际上,beanutils 支持在给定一组参数的情况下获得“接近匹配”。 请参阅 getMatchingAccessibleMethod()

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

Just a comment to your own answer; actually beanutils has support for getting "a close match" given a set of parameters. See getMatchingAccessibleMethod()

BeanUtils is really powerful and has lots of utility methods for inspecting classes. The same support is naturally available for constructors.

梦在深巷 2024-07-17 19:22:49

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

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

Try the FEST Reflection module. It's a fluent way to do Java reflection. For example:

 String name = method("get").withReturnType(String.class)
                         .withParameterTypes(int.class)
                         .in(names)
                         .invoke(8);
韬韬不绝 2024-07-17 19:22:49

如果您追求简单性,我创建了一个名为 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

If you're looking for simplicity, I have created a simple library called jOOR in order to facilitate access to the reflection API in Java. It supports the most essential actions without building up a huge API. Here's an example of what jOOR code looks like:

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
苯莒 2024-07-17 19:22:49

查看 Java 的脚本支持; 我相信它会帮助您解决您的问题。

Take a look at Java's scripting support; I believe it will help you tackle your problem.

节枝 2024-07-17 19:22:49

我强烈考虑也看看 springs ReflectionUtils 类。
非常强大的反射处理。

I would strongly consider also having a look at springs ReflectionUtils class.
Very powerful reflection handling.

临风闻羌笛 2024-07-17 19:22:49

要使这个问题起死回生:

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

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

TO raise this from the dead:

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

Apache Commons lang has exactly that method.
MethodUtils#invoke

分開簡單 2024-07-17 19:22:49

我已经开始创建一个库 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 中心获取它:
http://repo1.maven.org/maven2/com/ lexicalscope/ Fluent-reflection/ Fluent-reflection/

它目前缺少一些基本功能,例如对字段的访问,但它适用于方法。 可能需要一段时间才能达到真正的功能稳定点(例如一两年),因为我只是偶尔进行工作。 但它是按照相当高的质量标准开发的(我希望)并且它是开源的,因此如果它具有您需要的所有功能,您基本上可以像现在一样使用它(如果您想要,您可能需要稍微调整一下代码)使用已发布的较新版本)。 我当时正在一些生产代码中使用它。

它被设计为具有相当的可扩展性,因此您可以插入策略以松散耦合(组合)风格找到所需的方法。 因此,如果它没有您想要的确切方法查找策略,希望很容易添加它。

I have started to create a library com.lexicalscope.fluent-reflection:fluent-reflection
which integrates with hamcrest and lambdaj

You can write code like this; which calls all the post construct annotated methods in a class:

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

Blog post here: http://www.lexicalscope.com/blog/category/software-projects/fluent-reflection/

Documentation here: http://fluent-reflection.lexicalscope.com/

You can get it from maven central here:
http://repo1.maven.org/maven2/com/lexicalscope/fluent-reflection/fluent-reflection/

It has some basic features missing at the moment, like access to fields, but it works for methods. It will probably take a while to get to a really feature stable point (like a year or two), as I am only working on it occasionally. But it is developed to quite a high quality standard (I hope) and it is opensource so you can basically use it as it is now if it has all the features you need (you just might have to adjust your code a bit if you want to use newer versions that are released). I am using it in some production code at them moment.

It is designed to be quite extensible, so you can plugin in strategies to find the methods you want in a loosely coupled (compositional) style. So if it doesn't have the exact method lookup strategy you want, hopefully it is easy to add it.

三寸金莲 2024-07-17 19:22:49

reflections 项目,我相信它是 Java 8 的最新实用反射库与上面列出的其他度假村相比,它提供了更多的支持,最终是截至 2020 年 3 月进行一些高级反思行动的最佳方式。

内容如下:

发布了 org.reflections:reflections:0.9.12 - 支持 Java 8

...
Reflections 库每月从 Maven Central 的下载量超过 250 万次,并被数千个项目和库使用。 我们正在寻找维护人员协助审查拉取请求和管理版本,请联系我们。

...
Reflections 扫描您的类路径,索引元数据,允许您在运行时查询它,并可以保存和收集项目中许多模块的信息。

与Java标准反射结合使用,它应该可以满足您的所有需求。

There is the reflections project, which I believe the most up-to-date utility reflections library with Java 8 support compared to others resorts listed hereabove and ultimately the best way to do some advanced reflection actions as of March 2020.

It reads:

Released org.reflections:reflections:0.9.12 - with support for Java 8

...
Reflections library has over 2.5 million downloads per month from Maven Central, and is being used by thousands of projects and libraries. We're looking for maintainers to assist in reviewing pull requests and managing releases, please reach out.

...
Reflections scans your classpath, indexes the metadata, allows you to query it on runtime and may save and collect that information for many modules within your project.

Used in conjunction with Java Standard Reflection, it should satisfy all your needs.

转瞬即逝 2024-07-17 19:22:49

我最终同意了亚历克斯的建议。 BeanUtils 对 Bean 有很大帮助,但我不想单独使用 Bean。 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 建议的绑定,我避免了大多数有关转义的陷阱。 此外,我有一个干净、简单的界面,如果有必要,我可以将其替换为“真正的”实现。

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

I ended up going with Alex's suggestion. BeanUtils helps a lot for beans, but I don't want to work solely with Beans. FEST looks really cool and I've bookmarked it for further study, but like BeanUtils, it doesn't appear to solve what I consider to be the difficult problem here. Namely, given a method name and list of arguments, pick the method that best "fits" the arguments. If a method takes a float and I have a double, it should be smart enough to not reject that method because the signature doesn't match exactly.

Obviously, scripting languages built on the JVM solve this problem, but in a much more complicated way than I need due to language-specific optimizations. So, since this is a minor and experimental feature, I've chosen an expeditious solution using the scripting engine support (JavaScript, in particular) in Java 1.6. Here's the basic idea:

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

There's obviously a bit more to it, but this is the basic idea. I don't really like building up a string and evaluating it, but by using the bindings suggested by Alex, I avoid most of the pitfalls around escaping. Furthermore, I have a clean, simple interface that I can swap out with a "real" implementation if it proves necessary.

Any feedback or alternate solutions are more than welcome.

瑕疵 2024-07-17 19:22:49

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

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

它的灵感来自 Guava,因此您可以使用 Predicate 来过滤你喜欢的方法。

I wrote and open-sourced this code after reading this thread, maybe you can find it useful.

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

It's inspired by Guava, so you can use Predicate to filter the methods you like.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文