Is it possible to monkey patch in Java?

早过忘川 提交于 2019-11-28 10:46:01

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.

One ugly solution would be to put your own implementation of DefaultWidget (with same FQCN) earlier on the Classpath than the normal implementation. It's a terrible hack, but every other approach that I can think of is even worse.

Just my concept idea,

It is possible that use AOP, with bytecode engineering way, to inject a aspect to the calculateHeight method.

Then, you may enable you patch by ThreadLocal or else variable.

cglib is a Java library that can do some things similar to monkey patching - it can manipulate bytecode at runtime to change certain behaviours. I'm not sure if it can do exactly what you need, but it's worth a look...

It is totally possible to monkeypatch in Java, using Unsafe.putObject and a class finder. Wrote a blog post here:

https://tersesystems.com/blog/2014/03/02/monkeypatching-java-classes/

The object-oriented way of doing this would be to create a wrapper implementing IWidget, delegating all calls to the actual widget, except calculateHeight, something like:

class MyWidget implements IWidget {
    private IWidget delegate;
    public MyWidget(IWidget d) {
        this.delegate = d;
    }
    public int calculateHeight() {
        // my implementation of calculate height
    }
    // for all other methods: {
    public Object foo(Object bar) {
        return delegate.foo(bar);
    }
}

For this to work, you need to intercept all creations of the widget you want to replace, which probably means creating a similar wrapper for the WidgetFactory. And you must be able to configure which WidgetFactory to use.

It also depends on no client trying to cast the IWidget back to DefaultWidget...

Only suggestions I can think of:

  1. Dig through the library API to see if there's some way of overriding the defaults and sizing. Sizing can be confusing in swing (at least to me) , setMinimum, setMaximum, setdefault, setDefaultOnThursday, ... . It's possible there's a way. If you can contact the library designer(s) you might find an answer that will alleviate the need for unpleasant hacking.

  2. Perhaps extend the factory only overriding some default sizing parameter? depends on the factory but it might be possible.

Creating a class with the same name might be the only other option, as others have pointed out it's ugly and you're liable to forget it and break stuff when you update the api library or deploy in a different environment and forget why you had the classpath set up that way.

You can try using tools like PowerMock/Mockito. If you can mock in tests, you can mock in production too.

However these tools are not really designed to be used that way, so you'll have to prepare the environment yourself and won't be able to use the JUnit runners like you do in tests...

Well, I keep trying to post suggestions, and then I see that they won't work or that you've already mentioned you tried them.

The best solution I can think of is to subclass WindowDisplayFactory, then in the subclass's createView() method, first call super.createView(), then modify the object returned to completely throw out the widget and replace it with an instance of the subclass that does what you want. But the widget is used to initialize stuff, so you'd have to go change all of those.

Then I think of using reflection on the returned object from createView() and trying to fix things up that way, but again, that's hairy because so much stuff was initialized with the widget. I think I would try to use that approach, though, if it was simple enough to justify it over copying and pasting.

I'll be watching this, plus thinking to see if I can come up with any other ideas. Java Reflection sure is nice, but it can't beat the dynamic introspection I've seen available in languages such as Perl and Python.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!