It is possible in plain Java to override a method of a class
programmatically at runtime (or even create a new method)?
I want to be able to do this even if I don't know the classes at compile time.
What I mean exactly by overriding at runtime:
abstract class MyClass{
public void myMethod();
}
class Overrider extends MyClass{
#Override
public void myMethod(){}
}
class Injector{
public static void myMethod(){ // STATIC !!!
// do actual stuff
}
}
// some magic code goes here
Overrider altered = doMagic(
MyClass.class, Overrider.class, Injector.class);
Now, this invocation...
altered.myMethod();
...would call Injector.myMethod() instead of Overrider.myMethod().
Injector.myMethod() is static, because, after doing "magic"
it is invoked from different class instance (it's the Overrider),
(so we prevent it from accessing local fields).
You can use something like cglib for generating code on-the-fly
In java6 has been added the possibility to transform any already loaded class. Take a look at the changes in the java.lang.instrument package
For interfaces there is java.lang.reflect.Proxy.
For classes you'll either need a third-party library or write a fair bit of code. Generally dynamically creating classes in this way is to create mocks for testing.
There is also the instrumentation API that allows modification of classes. You can also modify classes with a custom class loader or just the class files on disk.
I wrote an article for java.net about how to transparently add logging statements to a class when it is loaded by the classloader using a java agent.
It uses the Javassist library to manipulate the byte code, including using the Javassist compiler to generate extra bytecode which is then inserted in the appropriate place, and then the resulting class is provided to the classloader.
A refined version is available with the slf4j project.
If I got it right, the main problem that concerns you is how to pass a static method delegate (like in C#), through the instance interface method.
You can check this article: A Java Programmer Looks at C# Delegates (archived), which shows you how to get a reference to your static method and invoke it. You can then create a wrapper class which accepts the static method name in its constructor, and implements your base class to invoke the static method from the instance method.
Related
I'm implementing an IntelliJ plugin for refactoring a huge amount of java classes.
Within a JavaRecursiveElementVisitor I want to change the signature of particular method calls.
Concretely, I want to change the parameter order for calls of static assertXxx methods in the context of upgrading from JUnit4 to JUnit5. Some test classes are already using JUnit5, so it is crucial to know which class was statically imported.
Probably this could be solved by using a ReferencesSearch, but I wonder if I can't get the class for which a static method is called, within the visitMethodCallExpression method via the PsiMethodCallExpression parameter:
#Override
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
// TODO: check if expression refers to org.junit.Assert.assertXxx or to org.junit.jupiter.api.Assertions.assertXxx
super.visitMethodCallExpression(expression);
}
I would prefer to stick on the visitor because since I have to do many changes within each class, I assume it would be more efficient to visit every class only once rather than invoking a ReferenceSearch again and again.
I'm using Dictionary class to localize my application, since I want my texts to be files outside of the application, so I can change them without the need to compile the app again.
To be able to get the strings, I created class StringIdentifiers, that had all the methods like:
public String minute(){
return getString("minute");
}
The method getString() basically just used a Dictionary to get the string from a JSON included into the page.
I then created subclass called Language, where I had some more logic (checking what language to use etc.). It all worked flawlessly, I used the Language subclass to access the Strings. Even in UIBinder.
Since there are more and more texts now, I decided to split these methods into separate classes. But since in Java I cannot do multiple inheritance, I decided to do it via interfaces. So instead of StringIdentifiers I created interfaces like: LoginTexts, MenuTexts, EventLogTexts etc. In these interfaces I specified default methods to get the appropriate strings. The Language class implements all the interfaces and also the getString() method.
Now it all works fine, I get instance of the Language class, I can use methods from the interfaces in the code, no errors.
BUT when it comes to UI binder, it doesn't show errors in editor, but at compilation it tells:
[ERROR] Could not find no-arg method named minute in type
com.company.project.client.locale.Language
Does this mean, that UI binder is not able to see inherited default method from the interfaces? Really? I mean in the Java code, it is working normally.
Im experiencing the same issue, however, after searching I discovered this clever work-around written by Jos31fr: https://github.com/gwtproject/gwt/issues/9629
Define the interface assuming that GWT supports default methods.
In the class implementing the interface, redefine the default method as a call to the super-class.
import com.google.gwt.user.client.ui.TextBox;
public class TestTextBox extends TextBox implements TestInterface {
public void setFoo(String bar) {
TestInterface.super.setFoo(bar);
}
}
This is Test class.
package com.reflection;
import com.reflection.test.A
public class Main {
public void setA() {
A a = new A();
}
}
Then, I used ClassLoader for accessing and manipulating classes, fields, methods, and constructors as the code below
Class cls = cl.loadClass("com.reflection.Main");
Actually I really want to get A class by using cls and already tried to use getDeclaredClasses and getClasses but the result was nothing.
You can't do that with pure Java reflection. Reflection will let you look at classes and their members, but not at the code inside a method.
The easiest thing to do is probably to do javap -v somewhere in the build process, parse the output for qualified class names and store them in a property file somewhere.
The harder version is to use a byte code tool like asm or ByteBuddy, write a visitor over all instructions in your class and store all classes from all instructions in a Map. While this is theoretically the elegant approach, it will probably be a nightmare.
As part of a larger project, I am attempting to achieve something that I'm not sure is possible, so am eager to see if anyone has any suggestions!
The overall system:
As a whole, my system should be able to be provided with a JUnit test class, that matches some provided interface. Classes will be then given that do not implement this interface, but need to be checked to see if they would be able to (a.k.a. if they implement all necessary methods). If so, some transformation should take place such that the JUnit test class can be run against it.
So far I have implemented:
- A package that loads other classes given a path and name, using URLClassLoader
- A package that runs a JUnit test case and returns the results, using JUnitCore
The problem:
1. At first, how could I run the JUnit test against a class that does implement the interface when the test is designed to match the interface? How do I (at runtime) dictate that the instance being tested by the interface is the loaded class?
Is it possible to then extend this, such that I could i) verify that it does match the interface (I assume using Reflection to check for corresponding methods?) and then ii) modify that class such that it can be tested using the JUnit test class?
Thanks for any advice that might help towards part of this problem. I appreciate my description may be lacking, so please comment if you have any extra information that would help you give any answer!
You can do everything you want with the reflection API. It sounds like you should start with the tutorial, and then come back here for specific questions. Given a Class object you can check if it implements a given interface, create an instance of it, and then treat it like any other class.
Edit: I don't think I got that from your question, but in that case you are looking for the Proxy part of the reflection API.
how could I run the JUnit test against
a class that does implement the
interface when the test is designed to
match the interface
Since you have the class you can use the isAssignableFrom method offered by the class such that
Class loadedJunitClass = clazz;
MyInterface impl = null;
if(MyInterface.class.isAssignableFrom(loadedJunitClass )){
impl = (MyInterface) loadedJunitClass.newInstance();
}
For the second question, you can check each method and see 1. If there exists a method with the same method name as defined in the interface, 2. If the method return type is the same from the interface and 3. If the method parameter types and length are the same. Of course 2 and 3 can be tricky to get right.
At that point I would just create an instance of that interface (anonymous or a private class), create a newInstance of that matching class. And invoke the methods through reflection within the interface's methods.
Now that is how you can get it done with reflection. I am not advicating reflection as you can imagine :)
For the first part of your question; if you have the loaded Class instance for the class you want to test you can construct one with newInstance() if it has a default constructor, or via the getConstructor methods if you need to pass parameters. You should be able to get this Class instance from the class loader.
For the second part. You should be able to check the public methods via getMethods() (again on the Class instance) then look through the returned array for the methods you want. There are methods on the Method class that will return information about parameters, exceptions and return type to verify they are what you require.
However, I am pretty certain it is not possible to modify the class at runtime to add the interface. It might be possible by modifying the byte code, but I don't know about that.
An alternative would be to write your test to call all method via reflection, then it doesn't matter what the type of the object is just that it has the right methods (which you've already checked).
If you want to make arbitrary class to implement given interface at runtime if its public API matches the interface, you have several options in Java. Creating java.lang.Proxy to bridge the target class, exposing YourInterface is the easiest way.
YourInterface i = (YourInterface) Proxy.newProxyInstance(
this.getClass().getClassLoader(),
new Class[]{YourInterface.class},
new InvocationHandler() {
#Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
//run method on your target class here using reflection
}
});
You can also use mixins in AspectJ or subclass your target class using CGLIB and add interface at runtime. But the proxy approach is not that hard-core to implement.
Assuming I have a class like
public class FooImpl
{
public void bar(){};
}
Is there a way to create its interface at runtime?
e.g.
public interface Foo
{
public void bar();
}
I have been looking into Javasssist and the truth is it's reflection that I'm interested in using the interface for (as Esko Luontola and Yishai stated)
So I want an interface that specifies a subset of the original class' methods to make a proxy from.
I came to realize there are more things to be concerned about like
Should you reuse that interface or create a new one each time?
The proxy class is effectively a new instance of type java.lang.reflect.Proxy, which might cause implications depending on the use case.
The last point made me wonder on how some frameworks manage to handle this, do they deep copy the object? do they encapsulate the proxy inside the original instance?
So maybe it's just easier (though maybe not as elegant) to require for the client code to create the interface for the class.
You can do it with some bytecode manipulation/generation during class loading, for example using ASM, Javassist or similar, maybe also AspectJ.
The important question is, why would you need to do that? No normal code can use the class through its interface, because the interface does not exist at compile time. You would either need to generate the code that uses the interface or use reflection - but in that case you might as well use the original class. And for the interface to be useful, you should probably also modify the original class so that it implements the generated interface (this can be done with the libraries I mentioned).
You can look at something like Javassist to create the class. You would go over the class with Class.getMethods() and have to implement the bytecode at runtime for the interface, and then use the Proxy class to bridge the interface and implementation.