How to override instance/concrete class's method runtime? (e.g. reflection, cglib)
-
16-02-2021 - |
Question
What I wanna do is a method that can
- generate instance of Class X (a class variable passed in arg) and
- override some of it's method
More specifically, the parent class X I want to override contains
- Contains no default constructor (e.g. all constructors with args)
- Constructors calling non-private method within the same class
Originally I thought it's quite simple to use reflection or something similar, Then I found there's limitation on implementing my requirement.
- For refection: Can only override "interface" via java.lang.reflect.Proxy http://download.oracle.com/javase/1.3/docs/guide/reflection/proxy.html
- for cglib: it cannot create instance of no default constructor and constructor calling non-private member methods http://insufficientinformation.blogspot.com/2007/12/spring-dynamic-proxies-vs-cglib-proxies.html
I think this is achievable, since Mockito can do all kinds of method injection runtime.
Please anyone give some advise, Thanks.
The pseudo-code I image is like this:
createAndOverride(Class X) {
X newObj = X.newInstance(args) {
@override
methodOfX(args2) {
...
}
}
return newObj;
}
- Original problem scenario
I was intended to test a Class which has several methods calling X1.get(), X2.get(), X3.get()
In some test case, I need to make Xn.get() to return something I can control for test (e.g. null)
Due to below constraint:
- But due to mock tool restriction to JMock 1.0 (I have no control :( ), so I cannot just simply mock Xn.get() to returns "someSpecifiedObjects"
- Xn has no null constructors and constructors calling non-private member
My workaround is self made Xn Class and pass them to test case to let Cn.get() to be expected
code example:
ClassToTest.SomeMethod(new X1() {
@override
get() {
return someSpecifiedObjects;
}
});
And this kind of thing is spread-ed over the Test Case.
Therefore, In order to reduce duplicate code, I would like to build a method to generate Xn instance with specified overrided method for test. e.g.
X1 x1 = createAndOverride(X1);
Then, the problem of this post comes
Solution
So what I think you need is a similar functionality to C#'s Reflection.Emit
:
- Using Reflection.Emit to create a class implementing an interface
- Java Equivalent of Reflection.Emit
- Dynamically Create Java Classes With JavaClassCreator
While I haven't done this myself, I think you should be able to use reflection/emission and dynamic type creation in order to achieve what you're looking for. However, I would still like to mention that if you're trying to test "functionality" that's not int he code path of the function you're testing, then you probably shouldn't be testing it at all. For example:
SomeObjectInterface get()
{
if(_someObjectStateIsSet)
{
// Return a concrete implementation A
return new ConcreteImplA();
}
else
{
// Return a concrete implementation B
return new ConcreteImplB();
}
}
In this case get has no code path that would return null
, so you shouldn't need to test for null
. I'm not sure if I understood your question 100% correctly, especially why you're testing for null
, but consider the above advice and see what works for you.
OTHER TIPS
are you looking for something like javassist? You can instrument code and inject your methods at runtime. I personally try to avoid byte code manipulation as much as possible. Can you not have these overrides in your code base rather than doing on the fly? May be something like wrappers?