Those Evil Interface Proxies
You know, Java is a really nice language. For having a C derivative syntax, its constructs are remarkably clean and consistent. Java seems to lend itself to well designed libraries and sane APIs. It also has probably the most vibrant community of any language, and definitely the best tool support (three cheers for Eclipse JDT anyone?). However, there are times, when I'm sitting by myself hacking away at some keen idea, that I find myself just gnashing my teeth at the language designers. Seriously, how complicated do these things have to be?!
Not many people know it, but Java has a (theoretically) really nice feature called reflective interface proxying. This allows an interface to be implemented dynamically by another class instance implementing the java.lang.reflect.InvocationHandler interface. All of the calls to the interface instance are dynamically proxied (hence the name) to the invoke(Object, Method, Object[]) method in the proxy instance. This allows you to do something like this:
public TestInterface {
public void print(String value);
}
public TestProxy extends InvocationHandler {
public Object invoke(Object proxy, Method method,
Object[] args) {
if (method.getName().equals("print")) {
System.out.println(args[0]);
return null;
}
return null;
}
}
TestInterface instance = Proxy.newProxyInstance(
TestInterface.class.getClassLoader(), new Class[]
{TestInterface.class}, new TestProxy());
Instance.print("Hello World!"); // prints "Hello World!"
//to stdout
Sorry for the verbosity, but this was about the simplest example possible which demonstrates proxying. In this case, it's not really apparent just how powerful this can be. However, one can imagine the possibilities. Other, more dynamic languages (like Ruby or even Objective-C) have this feature in the forms of method_missing and valueForUndefinedKey. Anyone who has used these features will know just how useful they can be. Java's dynamic method handling is obviously much more primitive, and as you can see, much more verbose...
It's really from this that a lot of my headaches for the past few weeks have stemmed. It all began when I was trying to store the proxied objects in a static Map within the proxy handler. This of course requires two critical methods: equals(Object) and hashCode(). Simple enough right? Well, not quite. It seems that while Java does provide the implementations for other methods defined in the Object class, equals(Object), toString() and hashCode() are looped back to the proxy handler. This is really counter intuitive since I didn't think that I overroad those methods, I didn't want to override those methods, and I didn't override those methods. The invocations where just mysteriously dropped into my lap.
The whole proxy API is like this: one kludgy twist after another. And just as soon as you're sure you've got it all straight, some bizarre exception stack trace shows up which ruins your afternoon. In short, it's a devilishly frustrating language feature with precious few examples with which to work.
It's at times like this that I really appreciate some of Eclipse's more basic editor features. Things like inline javadoc, basic content assist and click-to-source stack traces in the Console window. These helpful little tools add can save so much time it's really amazing. I mean, as cool as JavaRef is, I can't say that it's the absolute fastest way to develop when you're forced to look up the documentation at every other method invocation. Really what it comes down to is this: the more I use Eclipse JDT, the more I love its power and simplicity.
Big Ticket Releases
This was actually a fairly significant week, in terms of software releases. VMware announced the much anticipated release of its Workstation 6.0 product, and Eclipse 3.3 M7 showed its face on the Eclipse.org website. By a staggering coincidence (well, not really staggering, it just sounds better that way), these two products have a highly anticipated integration feature, which allows Eclipse to launch (and debug) a Java application within a virtual machine. Actually, this integration has supposedly been available since the second beta of WS 6.0. However, I've never been able to get it to work.
I'm quite literally pulling my hair out over this. Most of the time, Eclipse causes a window of some kind to fire inside the guest OS, but the window disappears and Eclipse hangs forever attempting to make a connection to the virtual machine. If I have Eclipse in debug mode, it will detect a ClassDefNotFoundException just after the window disappears. I've Googled around on this and it seems that this exception occurs when the virtual machines in either host or guest are not Java 5.0 compatible. However, I'm running Java 6.0 in both host and guest so I can't believe that this is the problem. It's really quite strange. If any of you have any ideas on this or have been able to get the Eclipse-VMware integration plugin working, I'd love to hear about it.
Until Next Time,
Daniel Spiewak
daniel@dzone.com
|