My goal is to access the byte[] representing the bytecode of a class without specifically knowing the location of the class files at runtime.
I have looked into two solutions and was able to get mild success out of one of them, but I was wondering if there might be other ways to accomplish it (or how I went wrong in the second solution that I couldn't get to work).
My first (mildly) successful solution was to use the java.lang.instrumentation ClassFileTransformer class to access the byte[] of the classes. Though this workek, I assumed that there must be a cleaner way to accomplish this.
My second solution was to use the -Xbootclasspath JVM argument to replace java.lang.ClassLoader with my own allowing it to have access to the byte[] of the classes loaded. I added a simple System.out.println debug message to confirm that the overriding of the ClassLoader was working, but it wasn't. I got this idea from this paper on the same subject. My class was made similarly to how the Integer class was remade in the linked paper. I also used a similar directory setup for the JVM argument looking something like this:
java -Xbootclasspath/p:.\out\production\boot\java\lang TestLoader
My thought is that the ClassLoader class specifically cannot be overridden using the method in the paper I linked.
I would be interested seeing why my attempt at overriding the ClassLoader did not work and also in hearing what else I could do to access the byte[] of classes.
Could you just read the class bytes using getResourceAsStream()?
InputStream is = String.class.getResourceAsStream("String.class");
Edit adding alternative:
(copied from comment)
Given all the possibilities that need to be covered, ClassFileTransformer and instrumentation API might be the way to go. I don't know what the requirements are for 'clean', but if the issue is having to specify command line arguments to the JVM you could try using the Attach API - you can attach to an already running Java process, push in your ClassFileTransformer, and look at all the classes already loaded in the JVM plus any that are loaded thereafter.
I think you've just got the boot classpath wrong. Assuming that the class loader classfile is:
.\out\production\boot\java\lang\ClassLoader.class
you should use:
java -Xbootclasspath/p:.\out\production\boot TestLoader
Related
I have a class which behavior I would like to change. I need to replace private method with another realization. Common reflection techniques allow to modify private variable or to invoke private methods. But I find little information about replacing entire methods.
I presume that there are advanced techniques to do so. May be its impossible with standard java reflection but there are probably other tools to recompile byte code in runtime.
Modify & replace:
One option is to mask the class with a modified copy (modify code, recompile code, add modified classes to the classpath before patched classes), similar to the approach used here to inspect how a normally unavailable method works.
If you do not have sources to modify, you can "reverse" almost any .class file into more-or-less readable source code using decompilers. Notice that, depending on licensing, you may not have permission to do so and/or to redistribute your changes.
Patch via agent:
You can also patch the methods using the -javaagent:<jarpath>[=<options>] commant-line option. The "agent" is a jar that gets to modify loaded classes and alter their behaviour. More information here.
Mock:
If you have control over where the methods are called, you can replace the target instance with a stubbed version. Libraries such as Mockito make this very, very easy:
LinkedList mockedList = mock(LinkedList.class);
// stubbing appears before the actual execution
when(mockedList.get(0)).thenReturn("first");
Even though Mockito does not support mocking private methods natively (mostly because it is considered bad manners to look at other classes' privates), using PowerMock allows you to do so (thanks, #talex).
You can't replace method in runtime (at least without hack into JVM). But you can replace whole class. There are several way to do it. For example you can use thing called "aspect".
But from my experience I can say that if you need to do this you have wrong turn somewhere in beginning of you way.
Maybe you better make one step back and look at whole picture
Instead of going for advanced techniques, there is a simple trick to achieve this.
If you class is part of an open-source jar, get source code of this class file from grepcode.com. Change the method that you want to change and compile it. And update your jar file/classpath with this updated class file.
I need to create a map of our domain classes simple names to their fully canonical names. I want to do this only for classes that are under our package structure, and that implement Serializable.
In serialization we use the canonical names of classes alot --it's a good default behaviour as its a very conservative approach, but our model objects are going to move around between packages, and I don't want that to represent a breaking change requiring migration scripts, so I'd like this map. I've already tooled our serializer to use this map, now I just need a good strategy for populating it. Its been frustrating.
First alternative: have each class announce itself statically
the most obvious and most annoying: edit each class in question to include the code
static{
Bootstrapper.classAliases.put(
ThisClass.class.getSimpleName(),
ThisClass.class.getCanonicalName()
);
}
I knew I could do this from the get-go, I started on it, and I really hate it. There's no way this is going to be maintained properly, new classes will be introduced, somebody will forget to add this line, and I'll get myself in trouble.
Second alternative: read through the jar
traverse the jar our application is in, load each class, and see if it should be added to this map. This solution smelled pretty bad -- I'm disturbing the normal loading order and I'm coupled tightly to a particular deployment scheme. Gave up on this fairly quickly.
Third alternative: use java.lang.Instrumentation
requires me to run java with a java agent. More specifics about deployment.
Fourth alternative: hijack class loaders
My first idea was to see if I could add a listener to the class loaders, and then listen for my desired classes being loaded, adding them to this map as they're loaded into the JVM. strictly speaking this isn't doing this statically, but its close enough.
After discovering the tree-like nature of class loaders, and the various different schemes used by the different threads and different libraries, I thought that implementing this solution would be both too complicated and lead to bugs.
Fifth alternative: leverage the build system & a properties file
This one seems like one of the better solutions but I don't have the ant skill to do it. My plan would be to search each file for the pattern
//using human readable regex
[whitespace]* package [whitespace]* com.mycompany [char]*;
[char not 'class']*
class [whitespace]+ (<capture:"className">[nameCharacter]+) [char not '{']* implements [char not '{'] Serializable [char not '{'] '{'
//using notepad++'s regex
\s*package\s+([A-Za-z\._]*);.*class\s+(\w+)\s+implements\s+[\w,_<>\s]*Serializable
and then write out each matching entry in the form [pathFound][className]=[className] to a properties file.
Then I add some fairly simple code to load this properties file into a map at runtime.
am I missing something obvious? Why is this so difficult to do? I know that the lazy nature of java classes means that the language is antithetical to code asking the question "what classes are there", and I guess my problem is a derivative of this question, but still, I'm surprised at how much I'm having to scratch my brain to do this.
So I suppose my question is 2 fold:
how would you go about making this map?
If it would be with your build system, what is the ant code needed to do it? Is this worth converting to gradle for?
Thanks for any help
I would start with your fifth alternative. So, there is a byte code manipulation project called - javassist which lets you load .class files and deal with them using java objects. For example, you can load a "Foo.class" and start asking it things like give me your package, public methods etc.
Checkout the ClassPool & CtClass objects.
List<CtClass> classes = new ArrayList<>();
// Using apache commons I/O you can use a glob pattern to populate ALL_CLASS_FILES_IN_PROJECT
for (File file : ALL_CLASS_FILES_IN_PROJECT) {
ClassPool default = ClassPool.getDefault();
classes.add(default.makeClass(new FileInputStream(file.getPath())));
}
The classes list will have all the classes ready for you to now deal with. You can add this to a static block in some entry point class that always gets loaded.
If this doesn't work for you, the next bet is to use the javaagent to do this. Its not that hard to do it, but it will have some implication on your deployment (the agent lib jar should be made available & the -javaagent added to the startup args).
I'm currently working on a Java project where I have a set of data which I wish to output in several custom formats. I have a class for each format, which takes the raw data and converts it accordingly. However, to begin with I am only implementing two or three of these formats, but wish to allow more formats to be added at a later date without having to do a massive rebuild of the application.
My idea was to create a DLL for each of the format classes, and have my application pass the data to be converted to each of these. This way, I can create a DLL later on and have my main application accessing it. (I would gladly listen to any alternative ways of doing this, as someone who has done this in C++/C# before this felt like the logical solution but it may not be applicable to Java)
My problem is that I have absolutely no idea how to do this - in C++/C# I could write this in a few lines of code but I'm not sure how it works with Java. At the risk of asking a terribly vague question, how can I do this?
Answers are greatly appreciated and cookies and tea will be offered. :)
Thanks in advance,
M
Edit: Sorry, just to add: I am also unsure how to create the DLL, which must be in Java for this project, to be read in the first place. Thanks. :)
Rather than using a DLL per se, it seems like what is wanted is a plugin architecture of some sort.
One reason why I wouldn't recommend using a DLL unless it is necessary is that linking Java code with native code will require using the Java Native Interface (JNI) which would probably require more effort than a pure Java solution.
One relatively simple way to do so is to use the reflection capabilities of Java.
From the information given, I would probably go along the lines of the following:
Define an interface for the output format.
Create a Java class implementing the interface.
Have the class available from the classpath.
Dynamically load the class using reflection. (Using the Class.newInstance method can instantiate objects from class files loaded by the ClassLoader.)
With these steps, it would be possible to implement a simplistic plugin which wouldn't require a full rebuild when support for a new format is required.
Step 1: Define the interface
Let's say we end up with an interface like the following:
public interface Outputter {
public void write(Data d);
}
Step 2: Make an implementation class
Then, we'll make an implementation class.
public class TextOutputter {
public void write(Data d) {
// ... output data to text
}
}
Then, compiling the above, we'll end up with a class file called TextOutputter.class.
Step 3: Make the class available from the classpath
When running the main application, we'll need to have the above TextOutputter.class in the classpath. Normally, one would tell the JVM a list of places to consider as the classpath, and that should include the above class file.
Once that is done, we should be able to load the above class using reflection.
Step 4: Dynamically load the class using reflection
Now, when we actually want to load the above class, we'd do something like the following:
// Note: We load the class by specifying the fully-qualified class name!
Class<?> clazz = Class.forName("TextOutputter");
// Then, we instantiate the class.
// Note that the following method will call the no-argument constructor.
Outputter outputter = clazz.newInstance();
// Now, we can give data to the TextOutputter object that we loaded dynamically.
outputter.write(...);
The Class.forName method is used to attempt to find the TextOutputter class from the default ClassLoader. Once we obtain the class as a Class representation, we can then instantiate an object of that class.
Instantiating the object can be performed by using the Class.newInstance method. If something other than the no-argument constructor should be used, the Constructor of the class would have to be obtained proceed to instantiate the object from there.
The object instantiates via reflection is then placed into a Outputter variable, so the write method can be called on the TextOutputter.
Adding more formats would entail the above process, but changing the fully-qualified class name (e.g. for String, the FQCN is java.lang.String) is all that is needed to load up a different class.
In a nutshell, that's what it will take to dynamically load class files and use it from your application.
(Just as a side note, I did not actually compile the above code, so there may be some errors here and there, but I hope I could illustrate the process it will take.)
I've made such things.
i created an open java based plugin architecture POJO based,that even did reload on the fly of updated plugin classes.
JNI is the interface for dealing with native code.
The only technical part was to rewrite a classloader that enabled DLL reloading dynamically at runtime.
But if you do only make "offline" updates, no such things are needed.
You can load a new DLL at any time with System.loadLibrary(). However you may need to load a java class for it to bind to.
You might find using an OSGi container helpful as this supports both load and unloading of modules (including shared libraries)
I would suggest using karaf with iPOJO but there are many others.
If you want write native codes (compiled to a DLL) to be used in java, you want to look at Java Native Interface (JNI).
Update you can use System.loadLibrary(String libName) (if you know the library name and the library path is set) or System.load(String filename) (library filename) to load library (DLL) in java.
I think you can ignore the JNI path. I have the impression you're using the term dll for lack of a better word, you don't really need a dll.
You could do the same thing in Java, but you'd put your filters in jar files instead of dll.
Define an interface for the file format filters to implement
Put each implementation into a jar, in a specific folder (like 'filters')
At one point in the app, iterate over the folder, generate classloader for the jars
Use reflection to find all implementations of your interface, and create a class for each
Call the methods to do their job
That's basically it.
Java SE 6 introduces the ServiceLoader class:
http://download.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html
If you want a proper modular approach consider the NetBeans Platform (especially if it is a desktop application) or OSGi.
I've been working on a fairly simple project for a class. I knew it was supposed to be written in Java, and I read enough of the Assignment description to have an idea what I was supposed to be doing, so I set about creating a nice, object-oriented solution ('cause it's Java, right?). When I finally get to reading the nitty-gritty details of the assignment, I come upon this little gem: The whole thing is supposed to be submitted as a single class file. It's too late to rewrite the whole thing now, so I tried to work around it by making all my classes static inner classes of the primary class. To my chagrin, I discovered that eclipse, at least by default, compiles the inner classes to separate class files still. I unfortunately don't know much about Java compiler settings, but I'm hoping theres a way to get them all compiled to one .class file. Is is it possible, or must I simply turn in what I've got with a note and take whatever my TA decides to dock me for it?
I'm afraid there is no such option. Each class is defined in its own class file. Even anonymous classes are defined in ParentClass$1.class
What I would suggest is to put a huge comment/documentation on why you think it is not good to put everything in one class. Of course it depends on the person "on the other end".
If one file, rather than one class is required, simply make a jar file.
If you are feeling brave you could create a jar for your application, encode it as a string in a your toplevelclass which extends a classloader and use this classloader to load the classes from the decoded jar file.
This is so crazy and shows so much knowledge of the Java platform it has to be worth extra credits.
As a TA, if a student send me a single java file, with an object-oriented design and nested classes, I would love it!
If the TA wanted the simplest solution to the problem and you over-engineered it, than it's of course another story.
Note that if the TA does not like nested classes and think they are bad, point him to NewSpeak and Gilad Bracha's posts. He's been involved in the Java Language Specification, he is an authority in the field and came up with a language entirely based on class nesting!
That said, should this be a single file, or single class file. If the former you can of course ZIP/JAR it, if the latter a little chat with the TA would be the way to go.
My problem is that I'm working on a project that requires me to run multiple instances of someone elses code which has many static attributes/variables, which causes all the instances to share those resources and, well, crash. I can run multiple instances of this other person's program if I create a .jar file off of it and open it multiple times by running the .jar in windows, but running calling the "main" method multiple times in my code (which is what I need to do) won't work.
I thought about creating a .jar and using Runtime.getRuntime().exec( "myprog.jar" ); to call the program multiple times, but that won't work for me since I have to pass an instance of my object to this new program and I don't think this solution would allow for that.
PS: This is also posted in the Sun forums, so I`ll post the answer I get there here or the answer I get here there naturally giving proper credit once I this is solved =P.
Remember that a static element in Java is unique only in the context of a classloader (hierarchy); a class is uniquely identified in a JVM by the tuple {classloader, classname}.
You need to instantiate isolated classloaders and load the jar using that class loader. Each loaded class (and thus statis elements) are unique in their classloader and will not interfere with one another.
I'd say you have three alternatives:
Refactor the legacy application so that it doesn't use static attributes. If you can do this, this may be the best solution in the long term.
Continue with your approach of launching the legacy application in a separate JVM. There are a number of ways that you can pass (copies of) objects to another JVM. For example, you could serialize them and pass them via the child processes input stream. Or you could stringify them and pass them as arguments. In either case, you'll need to create your own 'main' class/method that deals with the object passing before calling the legacy app.
I think you should be able to use classloader magic to dynamically load a fresh copy of the legacy application each time you run it. If you create a new classloader each time, you should get a fresh copy of the legacy application classes with a separate set of statics. But, you have to make sure that the legacy app is not on your main classpath. The problem with this approach is that it is expensive, and you are likely to create memory leaks.
The description is a little confusing.
If you are running the code multiple times, you are running multiple independent processes, each running in its own JVM. There is no way that they are actually sharing the values of their static fields. Java doesn't let you directly share memory between multiple VMs.
Can you elaborate more (ideally with examples and code) what the attributes are defined as and what kind of failures you are getting? This may be completely unrelated to them being static.
In particular, what exactly do you mean by shared resources? What resources are your programs sharing?
The proper approach was already suggested - using custom ClassLoaders. Another thing comes to my mind, which might seem ugly, but will probably do, and is a bit more object-oriented approach.
The legacy code is used for its operations, and it incorrectly uses static instead of instance variables. You can fix that using inheritance and reflection:
create (or reuse) an utility class that copies instance variables to static ones
extend the classes in question and provide the same instance variables as the static ones
override all methods. In the overriding methods use the utility to copy the state of the current object to the static variables, and then delegate to (call) the super methods.
Then start using instance of your class, instead of the legacy ones. That way you will simulate the proper behaviour.
Have in mind this is NOT thread-safe.