views:

661

answers:

7

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 "backend" 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.

Thanks!

+2  A: 

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

alex
Nope. I'm looking for something with a method like "Object invoke(Object object, String nameOfMethod, Object[] args)" that finds the right method (taking inheritance and type conversion into account) and calls it. Java scripting just let's me evaluate strings in an existing scripting language.
Dave Ray
Well, Java scripting does more than letting you invoke scripting languages from Java, if I'm not mistaken- it provides mechanisms to let scripting code interact with Java objects (referred as Binding in the docs), which looks very similar to what you are trying to do.
alex
... at least, taking a look at existing scripting implementations should help you
alex
Thanks Alex. I was able to build an acceptable solution (in terms of engineering work, anyway) using your suggestions. I'll post what I came up with when I'm not watching the kids. :)
Dave Ray
hehe, I wasn't advocating the solution you choose, but I'm glad it worked for you :)
alex
+2  A: 

Have a look at Apache Commons BeanUtils

Nils-Petter Nilsen
+1  A: 

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);
flicken
A: 

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.

Dave Ray
+2  A: 

Hi. Just a comment to your own answer; actually beanutils has support for getting "a close match" given a set of parameters. See http://commons.apache.org/beanutils/v1.8.0/apidocs/org/apache/commons/beanutils/MethodUtils.html#getMatchingAccessibleMethod(java.lang.Class,%20java.lang.String,%20java.lang.Class[])

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

Bent André Solheim
A: 

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

Roman
+1  A: 

TO raise this from the dead:

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

Apache Commons lang has exactly that method. http://commons.apache.org/lang/

Hexren