Hello StackOverflow Community,
I recently discovered Java Instrumentation and what great things you can do with it, so I decided to write a small library for me that simplifies some of these things.
I have the following method (simplified):
public static void editClass(Class<*> clazz) {
...
}
It adds a transformer via Instrumentation that transforms the bytecode of loaded classes with the name of clazz.getName().
So in my premain method, I can say
editClass(Foo.class);
My problem is, by specifying the class via a reference to it (.class), this class gets loaded before the transformer is added, so after that, I have to retransform the class which prevents me from adding/removing methods and so on.
So, is there a way to not load the class when using this class reference? Or an other way to implement this? I know that I could just pass the class name as an argument, but I would really like to make this whole library type-safe and make refactoring easier.
Thanks in advance!
If you want to call the editClass method from premain only and we assume that the Java Agent itself does not use the class otherwise, so that the class literal inside the editClass call would be the only trigger, you can do the following:
provide both methods, editClass(Class<?> clazz) and editClass(String qualifiedName)
write the premain method (or agent classes in general) using editClass(Class<?>) and enjoy compile-time safety regarding the existence of the classes referenced via literals
perform a static code transformation of the agent classes, replacing all calls of editClass(Class<?>) with editClass(String)
This shouldn’t be too hard, as you only have to replace all sequences of ldc packagename/Foo.class, invokestatic (Ljava/lang/Class;)V with ldc "packagename.Foo", invokestatic (Ljava/lang/String;)V.
It may become even easier when the method editClass(String qualifiedName) can handle the internal class names (using slashes instead of dots).
Since you said you “recently discovered Java Instrumentation”, this might be a good exercise in class file transformations
Use the transformed Agent classes which have no references to the classes to transform anymore, to perform the load time transformations
Related
I need to call a bunch of Class.forName() s on third-party classes but this causes the static initializers to run of all the affected classes. This running of the static initializers is a undesired side effect that I want to avoid because the logic pulls in all sorts of other dependencies and other garbage.
Is there a way to prevent these from running? I need the class object, not just info I can get by hacking the class binaries.
I am aware that classes need to be properly initialized before methods should be invoked. I am not doing anything with the code of these classes, I want them frozen.
If you are dependent on the real class containing everything the class consists of, you are stuck with the static initializers unless you patch your virtual machine.
If you just need class meta-information (e.g. method names of the class, implemented interfaces) you can go with a library like Reflections.
Your suggestion to use Powermock/Mockito to suppress the static initialization would go in a similar direction as the Reflections library. Both Test frameworks change the bytecode of classes before loading, resulting in slightly different classes than the original one.
Without using any additional libraries, you can just do:
Class.forName(className, false, this.getClass().getClassLoader());
Where the second argument is initialize , to flag whether you want the class initialising.
The class is initialized only if the initialize parameter is true and if it has not been initialized earlier.
The single argument call to forName is just a convenience wrapper:
Returns the Class object associated with the class or interface with the given string name. Invoking this method is equivalent to:
Class.forName(className, true, currentLoader)
See: Class.forName documentation (Oracle Java SE7)
I need to have an app that during run-time can load another class and deserialize one of it's instance successfuly so that it can run it's methods and read the member variables.
From what I noticed, you can not serialize methods in Java, so I'm thinking about serializing the class instance in project2, load the compiled class with ClassLoader in project1, instantiate it and assign the deserialized instance from porject2 in project1 to the instantiated loaded class.
The serialized class will inherit the same parent class in both projects.
Is this the best way to go? It's a school project so the requirements are that my app can accept any other type of class without changing the code.
TL;DR: My plan is to load a compiled class with the ClassLoader so that my project knows about that class (specifically the methods inside) and then load that serialized class instance inside the project so that I can get the data from the instance and together with the loaded class (now I know the methods aswell), run the methods on the deserialized instance.
You are mistaken. The ability to call a method on some object isn't related to serialization at all.
What I mean: the method implementation is not part of the serialized data! Java serialization only writes field data into that output stream.
The implementation of a method only depends on the class file of some Java class. You can serialize and deserialize your objects as often as you want to - but what happens when you call a method on such an object is only determined by the class file that the corresponding class loader loaded for you when first accessing the corresponding class.
If your goal is really just about "one class dumps an object into a binary representation"; and another piece of code loads that binary data; turns it into an object; to access that object; then you do not need two projects. You also do not need to worry about "the methods being" there. As long as your ClassLoader knows the class of objects to be de-serialized, everything will just work. Just pick an example tutorial, like this here and work through it.
But: when your requirement is to invoke methods or access fields of arbitrary objects; then you don't look into serialization, but into Java reflection.
But a word of warning there: reflections sounds easy, but be assured: there are many many ways for you to write slightly wrong code. And because reflection is basically a runtime thing, the java compiler doesn't help much. You write code that looks reasonable, it compiles, you run it, and you get exceptions throw at you.
In that sense, reflection is an advanced topic in the Java curriculum; and I think you should rather step back and clarify with your teachers what exactly they expect from you.
Given your latest updates: then simply look into that tutorial about serialization (and forget about the reflection part). And to answer your question: yes, that sounds like a viable approach. Can't say more; as you are not sharing code so far.
I'm familiar with various ways of intercepting method invocations using proxies, but I'm wondering if there's a way to detect field access / dereferences on some proxy using a library like Javassist or ASM? For example:
void detectFieldName(Function<Foo, Supplier<String>> f) {
Foo fooProxy = createFooProxy();
f.apply(fooProxy);
}
detectFieldName((Foo foo) -> foo.bar);
Ideally from this I'd like to know that a field named bar was dereferenced.
Looking at your updated use case: lambdas are desugared to synthetic (compiler-generated) methods, with a function object that forwards interface calls through the generated method (I haven't looked into exactly how this is implemented, but I think Brian Goetz has talked about it). You can just look in that method's bytecode (loaded from the class file; some of the ASM sample code does this) and read off the field access. Instrumentation is not required.
Note that you can't create a proxy to see field access; the field access is performed in the lambda method (or more generally, where the field is loaded) without executing any code in Foo. In fact, you don't even need to call the lambda if all you want is to get the field name, and if all you're using the Foo proxy for is the call, you don't need a proxy.
I'm not aware of any way to intercept field accesses as easily as java.lang.reflect.Proxy makes intercepting method calls.
The getfield and putfield bytecodes use symbolic descriptors that encode the class and field name, so you could use a Java agent to add method calls before or after each load and store passing the field name, object and value being loaded/stored. (This works best if you're only interested in a subset of fields, say all fields of a particular class.) Depending on your needs, you may also have to recognize reflective accesses to your fields by instrumenting use of java.lang.reflect.Field, the handle returned by MethodHandles.Lookup.findGetter/Setter etc. (which may involve interprocedural analysis or reasoning about string operations used to build the field name, etc.). You could also try instrumenting "just before" the library calls into some JVM-specific native functionality, but that ties you to one JVM implementation and your instrumentation may be skipped if the JVM intrinsifies (special-cases codegen for) reflective calls.
If you're willing to write C code, you can use the JVM Tool Interface watched field functions. This seems the easiest way to get information, but it's harder to do interesting Java-level things with (though you can call back into your Java support library from the JVMTI).
Without major hacks, this is not possible. Field access in Java is not bound dynamically. This means, any reading or writing to a field is hardcoded into all using classes. With a method proxy, one makes use of the fact you can override a method to determine behavior. For intercepting field access, one would need to intercept the class that is using a field. Some libraries emulate this behavior by replacing field access by synthetic accessor methods. This requires however some build time redefinition of all concerned classes throughout the entire project.
As for your example, you could in theory use a tool like ASM to extract the required information from the lambda expression. However, note that the lambda expression's code will be extracted into a method of the class of the method that uses the lambda expression. You might have trouble finding out which method it actually is that contains your lambda but the byte code for invoking the expression will merely look something like this:
InvokeDynamic #0:accept:(LFoo;)Ljava/util/function/Function;
As you can see, the byte code will only contain a possibly ambiguous signature. Otherwise, you could of course copy the lambda expression's logic into a new class where you changed the logic of a field access. Since lambdas are by definition interfaces, the creation of such a new class would actually be comparably easy. But the problem with the method detection remains.
Can a class add a method to itself at runtime (like from a static block), so that if someone is performing reflection on this class, they'll see the new method, even though it wasn't defined at compile time?
Background:
A framework I'm using expects Action classes to be defined that have a doAction(...) method, by convention. The framework inspects these classes at runtime to see what type of parameters are available in their doAction() method. For example: doAction(String a, Integer b)
I'd like each class to be able to programatically generate its doAction() method with various parameters, just-in-time when it is inspected. The body of the method can be empty.
It's not simple. Once a class is loaded by a classloader, there is no way to change the methods of loaded classes. When a class is requested, a classloader will load it and link it. And there is no way (with Java) to change the linked code or to add/remove methods.
The only trick that comes to my mind is playing with classloaders. If we delete a custom classloader, then the classes loaded by that classloader should be deleted or inaccessible too. The idea that comes to my mind is to
implement one custom classloader
load the dynamic class with that custom classloader
if we have an updated version of this class,
remove the custom classloader and
load the new version of this class with a new instance of the custom classloader
I leave that as food for thought, can't prove, if this leads to a solution or if we have pitfalls.
As a simple answer to the question: No, we can't change a loaded class like we can change the content of fields with reflection. (we can't add or remove fields too).
Andres_D is right, we can very well do so using custom class loading, here is a detailed guide on how to do this: http://www.javaworld.com/javaworld/jw-06-2006/jw-0612-dynamic.html?page=1
The article explains how to write dynamic Java code. It discusses runtime source code compilation, class reloading, and the use of the Proxy design pattern to make modifications to a dynamic class transparent to its caller.
In fact researcher in Austria have written a JVM that even allows reloading classes with different type hierarchies. They have achieved this by using existing thread save points to generate a complete 'side universe' of an object and all it's related references and referenced content and then once fully reshuffled with all required changes simply swap in all changed classes. [1] Here a link to their project http://ssw.jku.at/dcevm/ the oracle sponsorship certainly makes for interesting speculations on future plans.
Less intrusive changes to method bodies and fields are already possible in the standard java VM using the Hot Swap capabilities of the JPDA as introduced in Java 1.4:
docs.oracle.com/javase/1.4.2/docs/guide/jpda/enhancements.html#hotswap
I'm not sure whether it was the first one but this Sun employee's paper from 2001 appears to be one of the early proposals mentioning the capabilities of the HotSpot to Hot Swap. [2]
REFERENCE
[1] T. Würthinger, C. Wimmer, and L. Stadler, “Dynamic Code Evolution for Java,” presented at the 8th International Conference on the Principles and Practice of Programming in Java, Vienna, 2010.
[2] M. Dmitriev, “Towards flexible and safe technology for runtime evolution of java language applications,” in OOPSLA Workshop on Engineering Complex Object-Oriented Systems for Evolution, 2001.
I've never tried anything quite like that myself, but you should have a look at ASM, cglib, and Javassist.
No, that is not (easily) possible in Java.
It sounds like you are trying to use Java as if it is a dynamic programming language. For example, Ruby has open classes: you can add and remove methods from Ruby classes at runtime. In Ruby, you can also have a "method missing" method in your class, that will be called when you try to call a method that doesn't exist in the class. Such a thing also doesn't exist in Java.
There is a version of Ruby that runs on the JVM, JRuby, and it has to do very difficult tricks to make open classes work on the JVM.
You can have a doAction method which does whatever you would like the generated method to do. Is there a reason it needs to be generated or can it be dynamic?
It looks like there is no way to add method dynamically. But you can prepare an class with a list of Methods or an hash like:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
public class GenericClass {
private HashMap<String, Method> methodMap = new HashMap<String, Method>();
public Object call(String methodName,Object ...args)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Method method = methodMap.get(methodName);
return method.invoke(null, args);
}
public void add(String name,Method method){
if(Modifier.isStatic(method.getModifiers()))
methodMap.put(name, method);
}
public static void main(String[] args) {
try {
GenericClass task = new GenericClass();
task.add("Name",Object.class.getMethod("Name", new Class<?>[0]));
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
}
}
Than, using reflections you can set or unset the attribute.
I believe you need some byte code altering tool/framework, such as asm, cglib or javassist.
You can achieve this via aspects/weaving like it's done Spring, but I believe you still need to have the method defined first.
Proxy may help. But have to instantiate a Proxy every time you want to add or remove a method.
What I suggest should work for your situation:
1. You have an existing class MyClass with n methods
2. You want to include (n+1) th method which is not in the class while compiling in another .java source file
My way to solve it is Inheritance. Create a new .java source file for a Class MyClassPlusOne extending the first class MyClass. Compile this class and use the object. How can I compile and deploy a java class at runtime?
class MyClassPlusOne extends MyClass
{
void doAction(String a, Integer b)
{
int myNPlus1 = a+b;
//add whatever you want before compiling this code
}
}
I'm not sure that is possible. However, you could use AspectJ, ASM, etc. and weave these methods into the appropriate classes.
The other alternative is to use composition to wrap the target class and provide the doAction method. You would end up delegating to the target class in this case.
This is a rather old question, but I still found myself looking at it today so, just in case, I'll add my two cents.
If you are using Java 8+, you can define "default" implementations of an interface method, so you can just define the interface with all the extra methods with empty default implementations, and add the implements clause in the desired classes. This approach, in some cases, may be the easiest one.
If you don't have control over the definition of the classes, or you need compatibility with older Java versions, you can still define an interface containing all the required extra methods; but in this case, implement a "Decorator" class with a method that receives the object to "decorate" as parameter, and returns a DynamicProxy instance, wrapping the passed object with this interface.
If you are using Spring, the decorator can be added to the context as a #Component, so you can inject it wherever you need to use it. If any of the objects you need to inject are Spring Beans, you could implement a FactoryBean that uses the decorator to return the instances, so you can just forget about calling the decorator explicitly for them.
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.