I need to edit a single class file from within a jar.
I have successfully extracted the class file from the jar, and I have decompiled it and found the logic I need to change.
However, I'm unable to recompile this class file, because it imports libraries I don't have and don't know where to get (netbeans and iharder).
The needed files should all be within the jar, right? Can I use the jar for this purpose?
I do not understand much of Java's overarching syntax, so anything related to packages or jar file structure might go over my head...
The JVM just needs to be able to find the dependencies at runtime. Often, they'll be installed in a standard location (the classpath), rather than being bundled with the jar that uses them. However, you could theoretically even do something like download dependencies at runtime and load them via a classloader.
Apart from that, decompiling and recompiling is often not a good idea, since decompilation is a lossy and error prone process. It generally only works in simple cases, and has limitations, as you've discovered.
If you understand Java bytecode, you can edit the class by disassembling it with Krakatau, editing the .j file, and then reassembling. This allows you to edit any classfile without needing to compile, meaning you don't need the dependencies. It also works no matter how complicated the class is, and even works on obfuscated classes.
Related
A lot of times in Java we want to use some functionality that is given to us in the form of JARs(ex. some external library). Most often than not I've noticed that JARs contain .class files.
Since .class files represent compiled bytecode ready for use by the JVM, my question is the following:
How is it that .class files are all that's needed for us to make use of an external library? Maybe a certain JAR contains the class file called: Person.class. How am I able to reference this class in my code when all that the JAR file exposes is a .class file. Isn't the source code(.java file) what's important and what's needed? In the same way that I can have two classes in the same package, I'm able to reference one from the other, because the two .java files(not .class files) are in the same scope(just to give an example).
Excuse me if it's a dumb question, but I really want to understand this.
Even if you write your source code in .java files, they are eventually compiled to form .class files which store bytecode that can be interpreted easily. When you use the jar files in your project, all the class files inside those jar files are included in your classpath, hence enabling you to use them.
So in a JAR package, .class files are sufficient to be used as a dependency.
The Java compiler takes your Java code, which is something that humans can understand, into .class files, which is something that the Java Virtual Machine (JVM) can understand. The JVM then takes the .class files and runs them on your machine.
A .jar file is effectively a collection of .class files packaged up (under the hood, it's really little more than a .zip in disguise). When you add a .jar onto your classpath, you are telling the JVM that it is one more place it should look when it needs a particular class.
I am not sure if I totally got your question, but the JARs are simply compiled javacode, which means, that the semantic/logic etc of the code has not been changed. You need to be able to access the functions/classes etc of the java code you want to use, because otherwise you would not gain any advantage of using a JAR.
One advantage of the JARs is, that the source code of these libraries is already compiled. Since these .class files are compiled .java files, they are all you need to access the functions that were written in the .java file.
In my situation I have many .jar files being created from a build process. Before I do any debugging I want a way to quickly verify that my .java source matches the .class found in a .jar.
I figure that if I unzip the .jar and find the .class which matches my .java file then I should be able to determine if they're functionally the same.
How can I do this?
The first thing to realize is that compilation doesn't just use the specific .java file for the class being compiled. The compiler also uses information from the other .java and .class files available at compile time. For example, it may inline static final constants. Also, stuff like method overloading depends on which methods have been defined.
That being said, if you compile the same source file with the same compiler as before, you'll probably get the same, or a very similar class file. However, even with identical source files, different compilers (javac vs eclipse) and different versions of the compiler will produce different results.
Therefore, what I'd recommend is first try compiling everything and see if the classfiles match. If the class files don't match, try disassembling them with the Krakatau disassembler and do a diff on the diassemblies to see what the differences are. That will help you see if the difference is unimportant (such as a reordering of the constant pool) or if there are substantive changes to the bytecode.
You can use a java decompiler like http://jd.benow.ca/ in order to be able to view the corresponding source of your class file then you will be able to compare it with your java file
Maybe it would be enough for you if you can use a decompiler? Like one from IntelliJ IDE to see how is the source for you compiled class. You can even debug over the decompiled source.
jwrapper manipulates application jars somehow, and is resulting in a non-functioning jar: at runtime it throws a "MyClass cannot be cast to MyClass" type error. I believe this is caused by re-evaluating code that creates a class loader, leading to multiple instances of class MyClass being loaded.
The jwrapper docs don't describe the changes made to the jar, except for the use of pack200. I've tested pack200 in isolation, and it does not cause this problem.
I've also tested the jar built by jwrapper without using the wrapper executable, by passing it to "java -jar". So it's not jvm transmuting, or anything else that the wrapper is doing: the jar itself is broken.
UPDATE:
jwrapper allows skipping pack200, but then the install file is huge. Since pack200 works when run standalone, I could work around this if there were some way to tell jwrapper that the file is already packed. Using <Pack200Exceptions> doesn't help, because then it doesn't know the file is packed.
The underlying problem is that jwrapper sets the pack200 option "modification_time" to "latest", which changes the modification times of all the class files. At run-time this causes the clojure compiler to attempt to recompile the classes from source.
A work-around is to remove the .clj files from the jar prior to packaging, preventing the compiler from running. The lein ":omit-source" option is not sufficient here, because it leaves in .clj files from any dependencies. Instead you must use a pattern in :uberjar-exclusions, e.g.
:uberjar-exclusions [#".(clj|java)"]
as detailed here:
https://github.com/technomancy/leiningen/issues/1357
Is it possible to move the .class files in a jar from the default package
to another named package so that I can import and use them?
After browsing other questions here, I think jarjar might be exactly what im looking for,
but I don't have any idea how I can use it.
So my question is how to use jarjar to repackage .class files from the default package to another named package?
EDIT: I want to clarify something - I do not have the sources of the jar I want to repackage,
so I don't know how I could recompile the code.
Obfuscation and reflection is out of the question.
EDIT2: It appears its extremely simple to do using jarjar :)
java -jar jarjar.jar process rules.rules in.jar out.jar
rules.rules look something like this:
rule a net.ylivay.src.a
Problem solved!
To move classes into a different package, you not only need to change their location in the jar (or filesystem) directory structure, you also need to change the package declaration in the source files and then recompile the classes.
Instead of trying to repackage a jar, you should probably look at the powerful refactoring tools available in IDEs like Eclipse, which make this kind of thing simple. But since you say (in update to your question) that you don't have the source files, that is not possible.
The alternative would be to create proxy classes which invoke the ones you need in the default package using reflection. But not only is that unpleasant, but you say that reflection is out of the question.
So you cannot do what you want to.
I just asked a recent question about distributing executable JARs and their dependencies, and it made me realize that my understanding of JARs may be fundamentally flawed.
Thus, some might say "Hey now! This here is a duplicate question!" But I say nay, this question is a completely separate offshoot of this
original question, and is concerned with Java fundamentals!
If I have an application that depends on, say, the Apache Commons CLI as well as JODA Time, and I pack this app up into a distributable JAR, my original question was: Without including the CLI and JODA JARs in my JAR, how does the program run on the client-side???
I am now thinking that since my code, which uses CLI and JODA, gets compiled into classfiles, and that bytecode is what gets packaged, then there is no need to include CLI or JODA (or any other 3rd party JAR) in my JAR, since it is all now functioning bytecode.
Can someone confirm or correct me? This revelation, though late in coming, has been staggering.
No, that is not quite right. The key to everything is the classpath. Is all of the compiled code and/or other resources on the classpath? If you package everything up in one single jar, then yes, it is in the classpath and the JVM will locate all the resources to run. Otherwise, you need to specify (with a .bat or .sh file or something) all the resources that your application is dependent on, so the JVM will be able to appropriately look for those resources (be they Java code or properties files or whatever).
Also if I am reading your question right, are you assuming that the CLI and JODA code gets compiled into your code? If so, I hate to burst your bubble, but that is not the case. When your code compiles, it does not bring in dependencies (not in the sense you may be thinking). What it does at a conceptual level (correct me if I'm wrong JVM gurus) is it references other classes. Those references are what you are building when you code a class and compile it. At runtime the JVM will attempt to locate the compiled class behind the reference and THAT is where you either need the jar with those classes in the classpath OR you need those classes in your executable jar.
Make sense?
The third party libraries (JodaTime, for example) need to be on the classpath during runtime. Not "packaged within your JAR".
If your app is launched from a JAR. You should specify the classpath in the manifest file which is packaged within the jar - http://download.oracle.com/javase/tutorial/deployment/jar/downman.html
You can have ANT generate the manifest classpath for you using the manifestclasspath element - http://ant.apache.org/manual/Tasks/manifestclasspath.html