Java reflect, edit code in runtime - java

I am currently trying to edit a class file in runtime, Example:
Example.java with this code:
public static void execute(){
System.out.println("hello worl");
}
There is no easy way to edit the text in this example, Now i need code that edits the "hello worl" to "hello world" without having access to the Example.java and without restarting the program to edit byte code, Is this possible? I have searched many articles and have not found a defined answer.

This depends on how much access you have.
This simplest way is to alert that class before it loads and force JVM to load your version of it, but then it must be loaded by proper ClassLoader, by your nickname I can assume that you are trying to do some magic using Spigot minecraft engine? Then if you want to change class from other plugin all you need to do is to actually copy this class to your project and load this class in static block of your main class - just make sure that your plugin will load before that other one.
This will cause JVM to load this class before original one, and because of how spigot class loader works - it will be added to global map of plugin classes, so other classes with that name will not be loaded, that other plugin will use your class instead.
This is also possible in other places, not just spigot - but not in every application, as it must have similar class loading - with shared storage of classes for your plugin/jar and plugin/jar that you want to edit.
Other way is to use Javassist library to do something similar but in runtime:
ClassPool classPool = ClassPool.getDefault();
CtClass ctToEdit = classPool.getCtClass("my.class.to.Edit");
CtMethod execute = ctToEdit.getDeclaredMethod("execute");
execute.setBody("{System.out.println(\"hello world\");}");
ctToEdit.toClass(); // force load that class
Javassist will find .class file for that class and allow you to edit it, and then inject it to selected class loader (I think it is system one by default, you can use .toClass(ClassLoader) method too)
Most important part of this trick is that class can't be loaded before this code executes. This is why you need to provide class name manually, never do something like MyClass.class.getName(), this will break this trick.
Note that javassist java compiler is a bit tricky and limited, see their webpage to find more informations and useful tricks.
If class is already loaded... then you have last option.
You can do it using java agents via Instrumentation class - as it allows to reload classes in runtime (with few limitations, just like debugger, you can't change class schema, but you can change anything you want using ClassFileTransformer before class is loaded).
So you need to create special java agent that will edit this class before it loads, or after it load (but then with that few limitations) using https://docs.oracle.com/javase/7/docs/api/java/lang/instrument/Instrumentation.html#redefineClasses(java.lang.instrument.ClassDefinition...)
But normally to do so you need to add special flags or manifest entries to runnable .jar, if you are launching this code on JDK, then it is much easier - with few tricks you can create agent and attach it to your VM in runtime, there is a bit of code needed for that so I will just suggest to use byte-buddy-agent library, then you can get instrumentation with single line of code:
Instrumentation install = ByteBuddyAgent.install();
And you can redefine classes all you want, in your case I would also suggest to use Javassist library to edit code - as it is the easiest of available ones, but you can also use ByteBuddy or raw ASM, for javassist your code would look like this:
Instrumentation instrumentation = ByteBuddyAgent.install();
CtClass ctClass = ClassPool.getDefault().getCtClass(Main.class.getCanonicalName());
ctClass.defrost(); // as this class is already loaded, javassist tries to protect it.
CtMethod execute = ctClass.getDeclaredMethod("execute");
execute.setBody("{System.out.println(\"hello world\");}");
ClassDefinition classDefinition = new ClassDefinition(Main.class, ctClass.toBytecode());
instrumentation.redefineClasses(classDefinition);
If class is already loaded and you are on JRE and you can't change app start arguments for some reasons - so just any of that methods are not possible - write comment and describe way - I know some other magic, but it would take much more time to describe it, so I would need more information.

Related

Make a Java class visible from any ClassLoader

I'm using a Java Agent (Agent.class) to transform a method in a program (Program.class) in a way that includes a call to the Agent class.
public Program.getMultiplier()F:
ALOAD 1
ALOAD 2
FDIV
+ INVOKESTATIC Agent.getCustomMultiplier(F)F
FRETURN
I've inspected the class loaders and their parents of both Agent and Program classes, and their hierarchy looks like this:
Agent.class: AppClassLoader <- PlatformClassLoader <- null
Program.class: URLClassLoader <- PlatformClassLoader <- null
When the Program executes the added INVOKESTATIC instruction, it throws a ClassNotFoundException -- it cannot find the Agent class as it was loaded by a different class loader.
As a temporary solution, I've tried forcing AppClassLoader to become a parent of URLClassLoader with reflection, which works in older Java versions but has been removed since Java 12.
Is there a more reliable way to make sure my Agent class is visible from any class loader?
You can add classes to the bootstrap class loader using appendToBootstrapClassLoaderSearch. This makes the classes of the specified jar file available to all classes whose defining class loader follows the standard delegation pattern.
But this requires the classes to be packaged in a jar file. When you specify the Agent’s own jar file, you have to be aware that classes loaded through the bootstrap loader are distinct from the classes loaded through the app loader, even when they originate from the same jar file. Further, the classes loaded by the bootstrap loader must not have dependencies to classes loaded by by other class loaders.
If your getCustomMultiplier method is supposed to interact with the running Agent, you have to separate the agent and the class containing this method.
Have your Agent listen to the creation of new ClassLoaders and then attach instances of them to the new ClassLoaders.
This way you preserve your "Agent listens to ClassLoader" interface, even if it now extends beyond the one platform class loader you expected the Agent to listen to.
You may be able to do something specific that works for URLClassLoader, but not all classes are loaded by an instance of URLClassLoader. Any OSGi project won't, most web servers also use their own classloaders in order to support hot reload, etc.
As far as I know there's no way to just casually update some 'global parent of all classloaders' or inject one; there's no such parent, and even if there was, a classloader is free to ignore its parent entirely.
Therefore the general answer is: No, you can't do that.
But, let's get our hacking hats on!
You're an agent already. One of the things you get to do as agent is to 'witness' classes as they are being loaded. Just invoke .addTransformer on the instance of Instrumentation you get in your agentmain and register one.
When you notice the Program class being loaded, do the following:
Take the bytecode and toss it through ASM, BCEL, Bytecode Buddy, or any other java 'class file reader/transformer' framework.
Also open up a class from within your agent's code (I wouldn't use Agent itself, I'd make a class called ProgramAddonMethods or whatnot as a container - everything inside is for the program to use / for your agent to 'inject' into that program.
Add every static member in ProgramAddonMethods directly to Program. As you do so, modify the typename on all accesses (both INVOKESTATIC and the read/write field opcodes) where the etypename is ProgramAddonMethods and make it the fully qualified name of the targeted class instead.
inject the INVOKESTATIC as you already do, but, rewrite it so that it's going to its own class, as you just copied all the static methods and fields over there.
Then return the bytecode of that modified class from your transformer.
This 100% guarantees you cannot possibly run into any module or classpath boundary issues and it will work with any classloader abstraction, guaranteed, but there are some caveats:
Just don't attempt to futz with instance anything. Make it all static methods and fields. You can make fake instance fields using an IdentityHashMap if you must (e.g. a static IdentityHashMap<Foo, String> names; is effectively identical to adding private String name; to the Foo class.. except it's a bit slower of course; presumably as you're already in a mess o reflection that's acceptable here).
Your code has to be 'dependency free'. It cannot rely on anything else, no libraries other than java.*, not even a helper class. This idea quickly runs out of steam if the job you're injecting becomes complicated. If you must, make a classloader for your own agent jar using the appropriate 'thread-safely initialize it only once' guards, and have that load in a bundle that does have the benefit of allowing dependencies.
This is all highly complicated stuff but you appear to have already worked out how to inject INVOKESTATIC calls, so, I think you know how to do this.
This is precisely what lombok does to 'patch' some methods in eclipse to ensure that things like save actions, auto-formatting, and syntax highlighting don't break - lombok injects knowledge of generated notes where appropriate and does it in this exact manner because eclipse uses a classloader platform called Equinox which makes any other solution problematic. You can look at it for inspiration or guidelines, though it's not particularly well documented. You're looking in particular at:
The lombok.eclipse.agent package in the eclipseAgent source root.
The lombok.patcher project which is lombok's only actual dependency, in particular the lombok.patcher.PatchScript.transplantMethod method.
Note that the next method may also interest you: lombok.patcher's 'insert' doesn't move the method - it injects the body of the method directly in there (it 'inlines'). This requires some serious finagling of the stack and is only advised for extremely simple one-liner-esque methods, and probably is excessive and unneccessary firepower for this problem.
DISCLAIMER: I wrote most of that.

Custom compile-time class loading in Eclipse?

Is there a way to hook into the Eclipse compiler to specify custom class reading/resolving/loading logic while a Java source file is being compiled? I'm not sure what the correct term is, but essentially the compile-time equivalent of "class loading" that happens at run-time.
For example, say I have the Java source:
package foo;
import bar.Bar;
public final class Foo {
// getQux() returns type: qux.Qux
private final Bar bar = baz.Baz.getQux().getBar();
[...]
}
The compiler should request that 3 classes are read while compiling the source file foo/Foo.java:
bar.Bar - It is specified as an import.
baz.Baz - It is used in its fully qualified form (... = baz.Baz.getQux()...).
qux.Qux - It is an "indirect" dependency (it is returned by the call to baz.Baz.getQux(), which in turn is used to access a bar.Bar through the call to its getBar() method).
I'd like to be able intercept each of these "class requests" so that I can provide custom logic to obtain the class in question (perhaps it lives in a database, perhaps it it served up by some server somewhere, etc).
Also, I'd like it if no attempt was made to compile any of the source files in the Eclipse project until they are explicitly opened by the user. So in the example above, the 3 class requests (bar.Bar, baz.Baz, qux.Qux) aren't made until the user actually opens the source file foo/Foo.java. Ideally the list of source files in the project needn't be actual files on the filesystem (perhaps they too live in a database, etc) and a compile attempt is made only when a user opens/loads a source file.
I realize that, if possible, this has some drawbacks. For example, if I edit source file foo/Foo.java to make the class "package private", this will silently break any class that depends on foo.Foo until a "full" compile is done of the project. For now, that is fine for my purposes (there are things that I can do later to solve this).
Any ideas/suggestions?
Thank you!
Probably not, this would fall under the Java build path part of the JDT and I don't think it has that level of customization. There does not appear to be a documented extension point for this. To get a definitive answer you would need to look at the source. You could probably add this capability and it would mean that your would need to use an alternate version of the JDT, which might be difficult or impossible.

If a referenced Java class is not found, or blacklisted, when is this detected?

I wanted to use, inside Google appengine, a small library; one of the methods of one of its classes (say MyClass.writeToFile()) uses java.io.FileOutputStream, which is among the blacklisted classes (well, not white-listed).
Does this imply that MyClass will fail at classloading time, or just when (if) I try to invoke the offending method? At what point is that checking ("FileOutputStream not allowed") done? When loading MyClass file and detecting that it "refers to/depends on" FileOutputStream (I dont know if this is declared in the MyClass bytecode)? Or when trying to load FileOutputStream, while invoking MyClass.writeToFile() for the first time?
Further, assuming that the method MyClass.writeToFile() is not essential for my library (but MyClass is), is there some workaround, or should one refactor the library (and build, say two different jars, one full fledged and other sandbox-friendly) ?
Do a test deploy. Deployment should fail if I remember it correctly. Classes that are used by a certain class is part of the byte code, and google is verifying it.
Edit: I'm contradicting myself :) This thread indicates that deployment only fail if the FileOutputStream class is loaded:
GoogleAppEngine : possible to disable FileUpload?
Edit2: And this indicates that it is the class loader that is checking / stopping loading of forbidden classes: The Sandbox
Classes are lazyload upon first reference. If your code never tries to use FileOutputStream then there should be no problem.

How can I run my code upon class load?

Is there a feasible way to get my own code run whenever any class is loaded in Java, without forcing the user explicitly and manually loading all classes with a custom classloader?
Without going too much into the details, whenever a class implementing a certain interface read its annotation that links it with another class, and give the pair to a third class.
Edit: Heck, I'll go to details: I'm doing an event handling library. What I'm doing is having the client code do their own Listener / Event pairs, which need to be registered with my library as a pair. (hm, that wasn't that long after all).
Further Edit: Currently the client code needs to register the pair of classes/interfaces manually, which works pretty well. My intent is to automate this away, and I thought that linking the two classes with annotations would help. Next, I want to get rid of the client code needing to keeping the list of registrations up to date always.
PS: The static block won't do, since my interface is bundled into a library, and the client code will create further interfaces. Thus, abstract classes won't do either, since it must be an interface.
If you want to base the behavior on an interface, you could use a static initializer in that interface.
public interface Foo{
static{
// do initializing here
}
}
I'm not saying it's good practice, but it will definitely initialize the first time one of the implementing classes is loaded.
Update: static blocks in interfaces are illegal. Use abstract classes instead!
Reference:
Initializers (Sun Java Tutorial)
But if I understand you right, you want the initialization to happen once per implementing class. That will be tricky. You definitely can't do that with an interface based solution. You could do it with an abstract base class that has a dynamic initializer (or constructor), that checks whether the requested mapping already exists and adds it if it doesn't, but doing such things in constructors is quite a hack.
I'd say you cleanest options are either to generate Code at build time (through annotation processing with apt or through bytecode analysis with a tool like asm) or to use an agent at class load time to dynamically create the mapping.
Ah, more input. Very good. So clients use your library and provide mappings based on annotations. Then I'd say your library should provide an initializer method, where client code can register classes. Something like this:
YourLibrary.getInstance().registerMappedClasses(
CustomClass1.class,
CustomClass2.class,
CustomClass3.class,
CustomClass4.class
)
Or, even better, a package scanning mechanism (example code to implement this can be found at this question):
YourLibrary.getInstance().registerMappedClassesFromPackages(
"com.mycompany.myclientcode.abc",
"com.mycompany.myclientcode.def"
)
Anyway, there is basically no way to avoid having your clients do that kind of work, because you can't control their build process nor their classloader for them (but you could of course provide guides for classloader or build configuration).
If you want some piece of code to be run on any class loading, you should:
overwrite the ClassLoader, adding your own custom code at the loadClass methods (don't forget forwarding to the parent ClassLoader after or before your custom code).
Define this custom ClassLoader as the default for your system (here you got how to do it: How to set my custom class loader to be the default?).
Run and check it.
Depending on what kind of environment you are, there are chances that not all the classes be loaded trouugh your custom ClassLoader (some utility packages use their own CL, some Java EE containers handle some spacific areas with specific classLoaders, etc.), but it's a kind of aproximation to what you are asking.

Find Java classes implementing an interface [duplicate]

This question already has answers here:
How can I get a list of all the implementations of an interface programmatically in Java?
(11 answers)
Closed 9 years ago.
Some time ago, I came across a piece of code, that used some piece of standard Java functionality to locate the classes that implemented a given interface. I know the functions were hidden in some non-logical place, but they could be used for other classes as the package name implied. Back then I did not need it, so I forgot about it, but now I do, and I can't seem to find the functions again. Where can these functions be found?
Edit: I'm not looking for any IDE functions or anything, but rather something that can be executed within the Java application.
Awhile ago, I put together a package for doing what you want, and more. (I needed it for a utility I was writing). It uses the ASM library. You can use reflection, but ASM turned out to perform better.
I put my package in an open source library I have on my web site. The library is here: http://software.clapper.org/javautil/. You want to start with the with ClassFinder class.
The utility I wrote it for is an RSS reader that I still use every day, so the code does tend to get exercised. I use ClassFinder to support a plug-in API in the RSS reader; on startup, it looks in a couple directory trees for jars and class files containing classes that implement a certain interface. It's a lot faster than you might expect.
The library is BSD-licensed, so you can safely bundle it with your code. Source is available.
If that's useful to you, help yourself.
Update: If you're using Scala, you might find this library to be more Scala-friendly.
Spring can do this for you...
BeanDefinitionRegistry bdr = new SimpleBeanDefinitionRegistry();
ClassPathBeanDefinitionScanner s = new ClassPathBeanDefinitionScanner(bdr);
TypeFilter tf = new AssignableTypeFilter(CLASS_YOU_WANT.class);
s.addIncludeFilter(tf);
s.scan("package.you.want1", "package.you.want2");
String[] beans = bdr.getBeanDefinitionNames();
N.B. The TypeFilter is important if you want the correct results!
You can also use exclusion filters here instead.
The Scanner can be found in the spring-context jar, the registry in spring-beans, the type filter is in spring-core.
I really like the reflections library for doing this.
It provides a lot of different types of scanners (getTypesAnnotatedWith, getSubTypesOf, etc), and it is dead simple to write or extend your own.
The code you are talking about sounds like ServiceLoader, which was introduced in Java 6 to support a feature that has been defined since Java 1.3 or earlier. For performance reasons, this is the recommended approach to find interface implementations at runtime; if you need support for this in an older version of Java, I hope that you'll find my implementation helpful.
There are a couple of implementations of this in earlier versions of Java, but in the Sun packages, not in the core API (I think there are some classes internal to ImageIO that do this). As the code is simple, I'd recommend providing your own implementation rather than relying on non-standard Sun code which is subject to change.
Package Level Annotations
I know this question has already been answered a long time ago but another solution to this problem is to use Package Level Annotations.
While its pretty hard to go find all the classes in the JVM its actually pretty easy to browse the package hierarchy.
Package[] ps = Package.getPackages();
for (Package p : ps) {
MyAno a = p.getAnnotation(MyAno.class)
// Recursively descend
}
Then just make your annotation have an argument of an array of Class.
Then in your package-info.java for a particular package put the MyAno.
I'll add more details (code) if people are interested but most probably get the idea.
MetaInf Service Loader
To add to #erickson answer you can also use the service loader approach. Kohsuke has an awesome way of generating the the required META-INF stuff you need for the service loader approach:
http://weblogs.java.net/blog/kohsuke/archive/2009/03/my_project_of_t.html
You could also use the Extensible Component Scanner (extcos: http://sf.net/projects/extcos) and search all classes implementing an interface like so:
Set<Class<? extends MyInterface>> classes = new HashSet<Class<? extends MyInterface>>();
ComponentScanner scanner = new ComponentScanner();
scanner.getClasses(new ComponentQuery() {
#Override
protected void query() {
select().
from("my.package1", "my.package2").
andStore(thoseImplementing(MyInterface.class).into(classes)).
returning(none());
}
});
This works for classes on the file system, within jars and even for those on the JBoss virtual file system. It's further designed to work within standalone applications as well as within any web or application container.
In full generality, this functionality is impossible. The Java ClassLoader mechanism guarantees only the ability to ask for a class with a specific name (including package), and the ClassLoader can supply a class, or it can state that it does not know that class.
Classes can be (and frequently are) loaded from remote servers, and they can even be constructed on the fly; it is not difficult at all to write a ClassLoader that returns a valid class that implements a given interface for any name you ask from it; a List of the classes that implement that interface would then be infinite in length.
In practice, the most common case is an URLClassLoader that looks for classes in a list of filesystem directories and JAR files. So what you need is to get the URLClassLoader, then iterate through those directories and archives, and for each class file you find in them, request the corresponding Class object and look through the return of its getInterfaces() method.
Obviously, Class.isAssignableFrom() tells you whether an individual class implements the given interface. So then the problem is getting the list of classes to test.
As far as I'm aware, there's no direct way from Java to ask the class loader for "the list of classes that you could potentially load". So you'll have to do this yourself by iterating through the visible jars, calling Class.forName() to load the class, then testing it.
However, it's a little easier if you just want to know classes implementing the given interface from those that have actually been loaded:
via the Java Instrumentation framework, you can call Instrumentation.getAllLoadedClasses()
via reflection, you can query the ClassLoader.classes field of a given ClassLoader.
If you use the instrumentation technique, then (as explained in the link) what happens is that your "agent" class is called essentially when the JVM starts up, and passed an Instrumentation object. At that point, you probably want to "save it for later" in a static field, and then have your main application code call it later on to get the list of loaded classes.
If you were asking from the perspective of working this out with a running program then you need to look to the java.lang.* package. If you get a Class object, you can use the isAssignableFrom method to check if it is an interface of another Class.
There isn't a simple built in way of searching for these, tools like Eclipse build an index of this information.
If you don't have a specific list of Class objects to test you can look to the ClassLoader object, use the getPackages() method and build your own package hierarchy iterator.
Just a warning though that these methods and classes can be quite slow.

Categories

Resources