Is there a general “backend” library for Java reflection

六月ゝ 毕业季﹏ 提交于 2019-11-30 05:19:25
Bent André Solheim

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.

flicken

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);

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

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

Have a look at Apache Commons BeanUtils

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

Hexren

TO raise this from the dead:

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

Apache Commons lang has exactly that method. MethodUtils#invoke

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.

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.

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!