Java uses() wrapper

at 2005-05-17 in Examples by friebe (0 comments)

With the implementation of RFC #0022, a lot of new possibilities open up. I explored one of them this weekend: Integrating Java classes.

I installed JDK 1.5 by downloading the Windows webinstaller from java.sun.com and then choosing "Install all". After that, I uncommented the php_java.dll from the extensions list in php.ini and configured the Java library paths accordingly. The example script from the PHP manual worked out of the box:)

After playing around with the Java wrappers a bit, I noticed the following downsides:

  • Static methods could not be called as such.
    Prominent example: java.lang.Class::forName().
  • Exceptions would not blend in nicely with the XP exceptions.
    This is due to the fact that you need to check with java_last_exception_get() if there is an exception
  • The new Java('classname', constructor_args) approach looks clumsy
    I wanted Java proxy classes instantiation to look just like any other class.
  • A var_dump() of the proxy instances showed nothing exciting
    You'd only get something like object(java)(1) { [0] => 27 }

Considering the above list, I went ahead and wrote a uses wrapper. With this, we'd be able to load the classes just like XP classes, sort of like:

uses('java+xp://java.lang.Class'); 

The java wrapper now needs to be named sapi/java.uwrp.php so that lang.base.php can find it, so I created that file and began experimenting. My first idea was to create a wrapper-class on the fly in stream_open(). The class names need to be, of course, unique, and because there are so many classes in the XP framework with names identical to those in Java, I decided to name use the middle dot (·) to replace the dot (.) in the class names. Means: java.util.Date would become java·util·Date. This is possible as PHP permits quite a bit of characters to be used as class names:)

To catch the method calls, I'd use PHP4's overload extension on the wrapper. Problem is: Static method calls aren't intercepted, meaning that

$c= &java·lang·Class::forName($name); 

wouldn't trigger a user-defined __call() interceptor. OK, that rendered this approach useless.

The next idea I had was to use Java reflection to get a list of all methods and then create PHP wrappers for them. The Java reflection API offers Method.getModifiers() which returns a bitfield of modifiers (that is, public, private, protected, static, final, and so on), so that I'd be able to create different wrapper sourcecode based on whether a method was static or not. Or, in pseudo-code:
  1. Use java.lang.Class.forName() to retrieve a Class object
  2. Iterate over the results of its getMethods() method
  3. Check modifiers for ($modifiers & 8)
  4. Create wrapper function if not already existant (hint: method overloading!)

This approach worked!

Here's what I used to test my sourcecode:
  require('lang.base.php');
uses
('java+xp://java.lang.Class');

try
(); {
$c= &java·lang·Class::forName($argv[1]);
} if (catch('Exception', $e)) {
$e->printStackTrace();
exit
(0);
}

echo
'new '.$c->getName().'()= ';
$d= &$c->newInstance();
var_dump
($d->toString());

Here's what the above script outputs:
$ php java.php java.util.Date
new java.util.Date()= string(29) "Tue May 17 21:46:12 CEST 2005"

You'll find the uses wrapper at http://xp-framework.net/downloads/java.uwrp.phps - it needs to be saved to sapi/java.uwrp.phps.

There's still some bugs within this wrapper, but maybe you're encouraged to play around with it. I don't consider this particularily useful for the general case, because we can do almost everything Java can (why would I want to use java.util.Date, for example?) - but if you find this important, you might up writing an RFC:)



Subscribe

You can subscribe to the XP framework's news by using RSS syndication.


Categories

News
General
PHP5
Announcements
RFCs
Further reading
Examples
Editorial
EASC
Experiments
Unittests
Databases
5.8-SERIES
Unicode
Language
5.9-SERIES

Related

Find related articles by a search for «Java».