I know this is normally rather stupid, but don't shoot me before reading the question. I promise I have a good reason for needing to do this :)
It's possible to modify regular private fields in java using reflection, however Java throws a security exception when trying to do the same for final
fields.
I'd assume this is strictly enforced, but figured I'd ask anyway just in case someone had figured out a hack to do this.
Let's just say I have an external library with a class "SomeClass
"
public class SomeClass
{
private static final SomeClass INSTANCE = new SomeClass()
public static SomeClass getInstance(){
return INSTANCE;
}
public Object doSomething(){
// Do some stuff here
}
}
I essentially want to Monkey-Patch SomeClass so that I can execute my own version of doSomething()
. Since there isn't (to my knowledge) any way to really do that in java, my only solution here is to alter the value of INSTANCE
so it returns my version of the class with the modified method.
Essentially I just want to wrap the call with a security check and then call the original method.
The external library always uses getInstance()
to get an instance of this class (i.e. it's a singleton).
EDIT: Just to clarify, getInstance()
is called by the external library, not my code, so just subclassing won't solve the issue.
If I can't do that the only other solution I can think of is to copy-paste entire class and modify the method. This isn't ideal as I'll have to keep my fork up to date with changes to the library. If someone has something a little more maintainable I'm open to suggestions.
It is possible. I've used this to monkeypatch naughty threadlocals that were preventing class unloading in webapps. You just need to use reflection to remove the final
modifier, then you can modify the field.
Something like this will do the trick:
private void killThreadLocal(String klazzName, String fieldName) {
Field field = Class.forName(klazzName).getDeclaredField(fieldName);
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
int modifiers = modifiersField.getInt(field);
modifiers &= ~Modifier.FINAL;
modifiersField.setInt(field, modifiers);
field.set(null, null);
}
There is some caching as well around Field#set
, so if some code has run before it might not necessarily work....
Any AOP framework would fit your needs
It would allow you to define a runtime override for the getInstance method allowing you to return whatever class suits your need.
Jmockit uses the ASM framework internally to do the same thing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With