Is it possible to monkey patch in Java?

richq picture richq · Dec 19, 2008 · Viewed 8.5k times · Source

I don't want to discuss the merits of this approach, just if it is possible. I believe the answer to be "no". But maybe someone will surprise me!

Imagine you have a core widget class. It has a method calculateHeight(), that returns a height. The height is too big - this result in buttons (say) that are too big. You can extend DefaultWidget to create your own NiceWidget, and implement your own calculateHeight() to return a nicer size.

Now a library class WindowDisplayFactory, instantiates DefaultWidget in a fairly complex method. You would like it to use your NiceWidget. The factory class's method looks something like this:

public IWidget createView(Component parent) {
    DefaultWidget widget = new DefaultWidget(CONSTS.BLUE, CONSTS.SIZE_STUPIDLY);

    // bunch of ifs ...
    SomeOtherWidget bla = new SomeOtherWidget(widget);
    SomeResultWidget result = new SomeResultWidget(parent);
    SomeListener listener = new SomeListener(parent, widget, flags);

    // more widget creation and voodoo here

    return result;
}

That's the deal. The result has the DefaultWidget deep within a hierarchy of other objects. The question - how to get this factory method to use my own NiceWidget? Or at least get my own calculateHeight() in there. Ideally, I'd like to be able to monkey patch the DefaultWidget so that its calculateHeight did the right thing...

public class MyWindowDisplayFactory {
    public IWidget createView(Component parent) {
        DefaultWidget.class.setMethod("calculateHeight", myCalculateHeight);
        return super.createView(parent);
    }
}

Which is what I could do in Python, Ruby, etc. I've invented the name setMethod() though. The other options open to me are:

  • Copying and pasting the code of the createView() method into my own class that inherits from the factory class
  • Living with widgets that are too big

The factory class can't be changed - it is part of a core platform API. I tried reflection on the returned result to get to the widget that (eventually) got added, but it is several widget-layers down and somewhere it gets used to initialize other stuff, causing odd side effects.

Any ideas? My solution so far is the copy-paste job, but that's a cop out that requires tracking the changes in the parent factory class when upgrading to newer versions of the platform, and I'd be interested to hear other options.

Answer

Andy picture Andy · Dec 19, 2008

Perhaps you could use Aspect Oriented Programming to trap calls to that function and return your own version instead?

Spring offers some AOP functionality but there are other libraries that do it as well.