donderdag 6 mei 2010

New version! Focus on Java Reflection

Hello young ,and less young, padawans

I was gathering stuff to put in my next release, but it was nothing mind-boggling.
Until a couple of days ago...

I was trying to create a method that would be able to call an SBO (Documentum Service-Based Business Object) without having to import the SBO-interface and having to add the jar to my classpath.

I know this can easily be done using Java Reflection, but the problem was: I wanted to create one method to call any SBO.

Something like this:

public Object callSBO(String sboName, String methodName, Object... args){...}

Now, that isn't such a hard thing to do.
  1. Get the SBO-service
  2. use Reflection to get the method and invoke it
That is, when all your arguments are Objects!

I came across the problem of calling an SBO that takes an int value + some Objects.
The problem is that Java reflection wraps an int-value into an Integer to be able to put it in a Object-array.
Since we don't want to pass both an Object[] array and the corresponding Class[] array, we have to create the Class-array on the fly.
So we start with 2 ints, and unwillingly end up with 2 Integers.

Now I don't know if you have ever tried calling a function that takes int-values with Integer values through reflection, but I can assure you, it results in nice NoSuchMethodExceptions.

As a possible solution I tried to replace all primitive-wrappers-classes in the Class-array with primitive-classes, but what if you ever come across a method like this:
public void foo(int i, String s, Double d){...}

Ye, I know, functions that mix primitives with wrappers are rare, but exist nonetheless!  So ignoring that possibility would be a bad choice.
That left me with 2 options:
  1. Also pass an array with the corresponding classes to the method (no way!)
  2. Work some MAGIC 
I obviously decided to choose the latter, and I'll present it soon!

It's easy to use, just pass a Class/Object, methodName and an array of Objects to the method (as varArgs), and let SennMagic decide which values should be primitive and which should be wrappers.

I created the method to able to use in any case, and I also added a specific method callService(...) to DFCUtils.  

Now you can call any SBO without having to add the jar to the classpath of the (web)application.

Till soon...