I have a a static method in some legacy code, which is called by multiple clients. I obviously have no options to override it, or change behaviour through dependency injection. I am not allowed to modify the existing class.
What I want to do now is change the behaviour (that method - with the same signature and return type) using reflection.
Is it possible ? If not, can any design pattern rescue me ?
Thanks !
EDIT : There is some confusion on what can I change/modify. I cannot change any existing class/method - but I can add more classes to the project. The best I can do with the existing classes is annotate them. This is all done to avoid breaking anything in the existing code - which means a complete round of testing for a big project.
EDIT 2 : java.lang.Instrumentation is not available for Android - or else it sounds like a good fit !
Sounds like a weird requirement...
Anyway, reflection does not allow you to change code behaviour, it can only explore current code, invoke methods and constuctors, change fields values, that kind of things.
If you want to actually change the behaviour of a method you would have to use a bytecode manipulation library such as ASM. But this will not be very easy, probably not a good idea...
Patterns that might help you :
If the class is not final and you can modify the clients, extend the existing class and overload the method, with your desired behaviour. Edit : that would work only if the method were not static !
Aspect programming : add interceptors to the method using AspectJ
Anyway, the most logical thing to do would be to find a way to modify the existing class, work-arounds will just make your code more complicated and harder to maintain.
Good luck.
I guess you could have a look at Instrumentation class which have a method redefineClasses(ClassDefintion classDefinition).
The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance.
Hope this helps.
References: Javadoc
You can change method behaviour via Java's dynamic proxies mechanism. See this guide.
It will proxied all object methods. You can redefine only some methods by method name, like:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("put")) { // example for map
methods.get(method.getName()).invoke(target, args);
args[0] = "second"; // put again with "second" key
Object result = methods.get(method.getName()).invoke(target, args);
return result;
}
if (method.getName().equals("get")) { // example for map
System.out.println("Method get"); // you implementation
return methods.get(method.getName()).invoke(target, args);
}
return methods.get(method.getName()).invoke(target, args); // just do what initial method do
}
Related
I have a a static method in some legacy code, which is called by multiple clients. I obviously have no options to override it, or change behaviour through dependency injection. I am not allowed to modify the existing class.
What I want to do now is change the behaviour (that method - with the same signature and return type) using reflection.
Is it possible ? If not, can any design pattern rescue me ?
Thanks !
EDIT : There is some confusion on what can I change/modify. I cannot change any existing class/method - but I can add more classes to the project. The best I can do with the existing classes is annotate them. This is all done to avoid breaking anything in the existing code - which means a complete round of testing for a big project.
EDIT 2 : java.lang.Instrumentation is not available for Android - or else it sounds like a good fit !
Sounds like a weird requirement...
Anyway, reflection does not allow you to change code behaviour, it can only explore current code, invoke methods and constuctors, change fields values, that kind of things.
If you want to actually change the behaviour of a method you would have to use a bytecode manipulation library such as ASM. But this will not be very easy, probably not a good idea...
Patterns that might help you :
If the class is not final and you can modify the clients, extend the existing class and overload the method, with your desired behaviour. Edit : that would work only if the method were not static !
Aspect programming : add interceptors to the method using AspectJ
Anyway, the most logical thing to do would be to find a way to modify the existing class, work-arounds will just make your code more complicated and harder to maintain.
Good luck.
I guess you could have a look at Instrumentation class which have a method redefineClasses(ClassDefintion classDefinition).
The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance.
Hope this helps.
References: Javadoc
You can change method behaviour via Java's dynamic proxies mechanism. See this guide.
It will proxied all object methods. You can redefine only some methods by method name, like:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("put")) { // example for map
methods.get(method.getName()).invoke(target, args);
args[0] = "second"; // put again with "second" key
Object result = methods.get(method.getName()).invoke(target, args);
return result;
}
if (method.getName().equals("get")) { // example for map
System.out.println("Method get"); // you implementation
return methods.get(method.getName()).invoke(target, args);
}
return methods.get(method.getName()).invoke(target, args); // just do what initial method do
}
I come from a C++ background and I am currently learning Java. One question arose when I have tried using some third party libraries. How do I determine if the call to a method taking an object reference as parameter modifies the object?
In C++ this is clear thanks to the use of the const keyword. If the method signature is:
void foo(Boo& boo);
I know that the referenced object might be modified, while if the method signature is:
void foo(const Boo& boo);
The compiler guarantees that the referenced object is not modified.
I haven't seen something analogous in Java, as only the reference itself can be declared final, not the referenced object, and a final argument doesn't make much sense in the first place since it is passed by value anyway. Therefore, when I see a method such as:
void foo(Boo boo) {...}
How do I determine if the object referenced by boo is modified inside the body of the function (maybe using annotations)? If there is no way to know, is there some widely used convention or some best practices to avoid confusion and bugs?
how do I determine if the object referenced by boo is modified inside the body of the function (maybe using annotations)?
The only way is to read the code unfortunately.
If there is no way to know, is there some widely used convention or some best practices to avoid confusion and bugs?
The common convention is to pass an object which cannot be modified, using a wrapper if needed. This ensure the class cannot modify the object.
List<String> readOnly = Collections.unmodifiableList(list);
If the object is Cloneable, you can also use clone() but another common approach is to use a copy.
List<String> readOnly = new ArrayList<>(list);
If you care about such behaviour, unit tests can show whether a method modifies an object or not. If you have unit tests already, it is usually one or two lines extra to check for this.
There's no such facility built in to the language, unfortunately. A good defensive practice is to define the data objects you pass around as immutable (i.e., without any public method that allows modifying their state). If you are really concerned about this, you could copy/clone an object before passing it to a method you don't trust, but this is usually a redundant precaution.
NOTE: this answer is a more detailed version of
You can also write purity or side-effect annotations in your code — mernst
There exists the Checker Framework among the various things it can check at compile-time via annotations is the IJG Immutablity checker. This checker allows you to annotate object references with #Immutable or #ReadOnly.
The problem is that you often would have to annotate the library yourself. To ease your task the Checker Framework can automatically infer part of the annotations; you will still have to do much yourself.
A side effect analysis is not built into the Java language.
You can perform side effect analysis via manual inspection, but several tools exist to automate the process.
You can use an inference tool (1, 2, 3) to detect whether your code side-effects a parameter.
You can also write purity or side-effect annotations in your code and then use a checking/verification tool (1, 2) to ensure that your code conforms to the annotations you have written.
All of the above-linked tools have limitations, but you might find them useful. If you know of other tools, mention them in comments.
How do I determine if the object referenced by boo is modified inside
the body of the function (maybe using annotations)?
I must agree with other answers that there is no direct way to determine that method will modify your object or not and yes to make sure that method can not modify your Object you all have to do it is from your side.
If there is no way to know, is there some widely used convention or
some best practices to avoid confusion and bugs?
Here the method name comes to the scene. Moving ahead with the naming convention of method we have to take a look at some method declarations which clearly convince you that your Object will not be changed at all.
For example, You know that Arrays.copyOf will not change your actual array, System.out.println(boo) will not change your boo
Method names are real weapons to provide as much information as possible to the method user.(Yes! it's always not possible but quite a good practice to follow.)
Let's consider it in your case that say printBoo will only print, copyBoo will only copy, clearBoo will reset all attributes, checkAndCreateNewBoo will check your boo Object and create new if required.
So, ultimately if we can use them in a proper way caller can be assured with the fact that Object will remain the same after calling the method.
As everyone says, prefer using immutable objects and also avoid void methods
The available purposes of methods like this
void foo(Boo boo) {...}
are to change the state of the object itself or change the object passed as a parameter
void completOrder(Order order) { ... }
//or
void parserTokenEnded(String str) { ... }
There is a way , that the method developer should mark parameter as final , if it is not going to modify the parameter.
public void test(final Object param)
However very few people follow this , so it is difficult to know. However good programmer follow this rule , especially writing the api. If you want to write method and expose it. Make param final to indicate that passed object is not going to be modified.
Is it possible to set a default behaviour for custom (non-native) methods/functions in Java?
For example, I would like to change the default "Function" to do a System.out.println("message") whenever called.
So, when a custom method/function is being created:
public String testMethod()
{
//custom code
}
it should execute the newly added default behaviour (in this case the system output), before the custom code is run.
Even if this would be a bad excercise, is it possible? Maybe by extending the function class or something?
One way is using Aspect-oriented programming (AOP) for Java: Aspect/J. For what you want, AOP would let you inject code in your program at specific points, e.g. having specified methods execute some println code upon entering or exiting the method. [AOP has a much larger purpose than this simple use for printing debug statements, but I'm trying to stay on target for answering the question.]
This article (possibly somewhat dated) shows an example similar to what you want:
http://www.developer.com/java/other/article.php/3109831/Simplify-your-logging-with-AspectJ.htm
It sounds like you want either aspect-oriented programming (e.g., AspectJ) or byte-code weaving (e.g., ASM or cglib).
Maybe, you should look at java.reflect.Proxy.But it requires that you create one proxy per class for which you want to monitor method calls.
An example :
#SuppressWarnings("unchecked")
public static <T> List<T> traceList(final List<T> list) {
return (List<T>)Proxy.newProxyInstance(
ProxyTest.class.getClassLoader(),
new Class<?>[]{List.class},
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("enter "+method);
try {
return method.invoke(list,args);
} finally {
System.out.println("exit "+method);
}
}
});
}
If you only need to do this for your own classes and not for classes from the Java library or that you get from someone else, then this is what Object-Oriented Programming is all about. Create your top level class, put this function in it, and then derive any other classes from there.
I am implementing a sort of ORM in Java. I am trying to do a static find method that is only in the parent class. Let me get to the point:
public class DB {
public static Object find (int id) {
// i want to return anew instance of the calling subclass
}
}
public class Item extends DB {
// nothing here
}
public class Test {
public static void main () {
Item i = (Item) Item.find(2);
...
}
}
I don't know how to have the find method know which of its inherited class is calling it, so that i can return the right instance (and maybe call the right constructor, etc.) And the inherited class could be anything, no limit.
I've tried stacktrace, but it's only traced from Test to DB.
Any ideas?
Thank you everyone!
Static methods are not inherited, so you can't do this. A common approach to this problem (not including using one of tons of available ORM solutions) is to split your class hierarchy into two:
"Entity" (e.g. classes representing your actual data)
and "DAO" (Data Access Object) - classes that contain methods to manipulate data persistence.
A word to the wise: It's probably a bad idea to try and implement your own ORM. Projects like hibernate have covered this task in great detail, so if you roll your own you are likely to reinvent the wheel and possibly attempt to solve problems that have already been solved.
More on topic, ChssPly76 is correct in that you cannot accomplish this because of how static methods are handled in Java. When the VM loads the bytecode for the static method invocation, it will perform a lookup to find where the method actually is located. It won't find it on the Item class, so it will instead bind the call to DB.find.
However! It may be possible to achieve what you are trying to do with some bytecode wrangling. Viewing the bytecode (using javap -c) for the static method call in your example, we get the following:
invokestatic Method Item.find:(I)Ljava/lang/Object
Thus, once your call reaches DB.find, you could follow the stacktrace back to the callsite, and then inspect the bytecode at the callsite to retrive the actual target of the call. In theory, anyway, as I haven't seen this myself in practice. Also, beware of hacking bytecode like this, for here be dragons.
Kudos for identifying the active record pattern, and wanting to use it in Java. I do agree it's a design pattern that makes more sense than most DB access patterns found in Java, and it's one of the strengths of Ruby and PHP.
I think you may find the "Generic DAO" article at IBM developerworks useful.
Short: use Generics wisely.
I have huge class that I need to build stub for.
To give you picture it is Messages class of the GWT. Often this is class with dozens of methods that return String.
With JMock I can do stubbing, but I will end with allowing each method... This is not something that I would like to see.
Is there something that will automatically build the stubs for each method? I need this methods to return something predefined, like empty string, but I will be happy with any suggestions.
In JMock you can allow the methods you care about with explicit results and then allow any other method of the messages object with an allowing statement that does not include a method. E.g.:
allowing(m).getBlah("something");
will(returnValue("foo"));
allowing(m); // matches anything else, will return some default value if called
But...
If you are just stubbing a bunch of getter methods, a mock object framework is the wrong tool to use. Mock objects are used for testing that the object under test sends the correct commands to neighbouring objects to effect change in its environment.
It's often easier to create a stub class if the interface that only contains getters. Or you can use Usurper to generate stubs automatically.
For an interface you can use the functionality of java.lang.reflect.Proxy. Assuming that you want to stub answers for the MessageConstants class, the code will look similar to:
InvocationHandler handler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (String.class.equals(method.getReturnType()))
return "proxy generated method return";
throw new AbstractMethodError("Not implemented");
}
};
Class<?> proxyClass = Proxy.getProxyClass(MessageConstants.class.getClassLoader(), new Class[] { MessageConstants.class });
MessageConstants messageConstants = (MessageConstants) proxyClass.getConstructor(new Class[] {InvocationHandler.class}).newInstance(new Object[] { handler });
System.out.println(messageConstants.description());
messageConstants.getBoolean("someBoolean");
and will result in
proxy generated method return
Exception in thread "main" java.lang.Error: Not implemented
at xxx.Application$1.invoke(Application.java:48)
at $Proxy0.getBoolean(Unknown Source)
at xxx.Application.main(Application.java:64)
The InvocationHandler drives the stubbing, while the rest is just plumbing.
Glad to see you found an answer. Just for further info, jMock allows quite flexible specifications of how you match methods, see http://www.jmock.org/match-object-or-method.html. For example, you can do this sort of thing:
allowing (any(Object.class)).method("get.*").withNoArguments();
to match any getter.
S
If you use EasyMock, you only need to specify behavior/expectations/stubs for the methods you actually expect to be called and used.
After using both JMock and EasyMock, I have to say that EasyMock's API is about 10x easier to use, and since the interface is mostly statically-typed, it's refactoring safe as well (you are using Strings for method names, etc.).