I have tried to decompile .class file with JD. BUt i got Strange code in it(Static call to a non static method, Classname.this.method etc.) .
Could you please tell me whether it will give 100 percent source code or not?
No, java decompilers can't give you the exact source code back. Many compiler optimizations will not be reflected back in the generated file.
Related
I was inspecting the class file format since I wanted to add source code to the class file (which was possible in early Java versions) but all I found was a SourceFile attribute and the SourceDebug attribute. I was looking for the complete source code of the class to be bundled with the class file to ease the post-processing pipeline.
Does anyone know if my memories are wrong or how I can bundle the complete source code of a class within the class file so that I do not have to look up for the java-file when I want to check the source code?
Is there a compiler switch to do that?
Javac has a -g option adding additional debug information. Can someone tell me whats are the information it adds? Without the -g switch it generates lines of code index and source file information.
The main problem I have is generate a class file but only have a reference to a source file that might change. I want simply to bundle up source and class file.
In maven I can simply copy over all the source files to the target directory but would might be incompatible with Eclipse, IntelliJ and NetBeans IDE (and what not)... .
Using a decompiler will also provide a way to extract a useful representation of the source code since most decompiler will value the lines of code information and position the decompiled structures accordingly within the source code.
Since some scenarios will require access to comments and a correct representation on a char by char level, the decompiler would be a second rate solution.
One possible solution I found is defining a new class-file attribute (which is legal) that contains the source. Since the source is huge when compared to the class file, the content might be best compressed (yielding a 1:5 to 1:10 ratio).
This way the class file and the sources stay bundled.
The JVM specification guarantees that every JVM/Tool has to ignore unknown attributes.
I will invest into a wrapper of javac application, that ensures the source was not modified during compilation (and if yes, redo the compilation process) and after compilation is done adding the source code as a class-file attribute.
Since this will be incompatible to the IDE-build cycle of Eclipse (and most likely IntelliJ and NetBeans) it will also require a special post processor.
So integration will also require alternatives to the JavaBuilder.
Once the source code is attached to the class file in question it is very easy to do a lot of advanced stuff with it that helps with both maintaining and managing code. For me its important that the source code and a class stay together and the source information is a 100% percent equal to the source code it was compiled from.
This is a very simple question:
When you compile a java program, it is converted to byte code, so therefore, every line number of the .java or .class file is missed (I think so, probably I am wrong..). So, when you print a stack trace, how does it manage to get all the class names and line numbers that were in the call stack? I think that I may be missing something here, but I couldn't find anything related to this.
When you compile a java program, it is converted to byte code
Correct.
so therefore, every line number of the .java or .class file is missed (I think so, probably I am wrong..).
You're wrong. Line number information is embedded into the .class file unless you use the -g compiler option in certain ways.
If line numbers are present, then the java compiler created bytecode with the debug flag set to true. This can be achieved using java -g
From Oracle's javac documentation:
-g
Generate all debugging information, including local variables. By default, only line number and source file information is generated.
-g:none
Do not generate any debugging information.
-g:{keyword list}
- Generate only some kinds of debugging information, specified by a comma separated list of keywords. Valid keywords are:
source
Source file debugging information
lines
Line number debugging information
vars
Local variable debugging information
How to look into code, that was generated after complilation?
I want to watch it and find how it was changed(because I particularly interested in type erasure).
I mean I can look into assembly code using javap -c SomeClass.class.
But how to look into generated code(with type erasure)?
got to Documents\NetBeansProjects\yourProjectName\build\classes\yourPackageName here you will see all your .class files that was generated after compilation and open them using any text editor.
Note: the .class files might contain some binary data and you will see some strange symbols
Note: an internal class will have the same name as its outer class but it will start with $ sign
After short amount of time I found Java Decompiler JD-GUI. It seems that the thing I was looking for. Sorry if did not clarify the question properly.
I had a .class file which I wanted to decompile. I tried JAD but it resulted in usual break, goto and return statements which resulted in compilation error in the generated source code by JAD. I had a hard time trying to resolve those compilation errors and everytime I tried to fix a goto statement with return statement, it would introduce other compilation errors.
I then had to hire a freelancer on odesk and the job was done. I wanted to know the exact procedure to be used to decompile the following .class files which can help me and others in future regarding these messy goto, return and break statements added by JAD.
https://drive.google.com/file/d/0ByGLlk1Fq3QIYzVaMGZ4MEVzcjg/edit?usp=sharing
In principle, valid class files can be generated by many more languages than just java, but only class files generated by a standard java compiler can be decompiled into valid java.
To add insult, even class files compiled from java source may not decompile properly, if the code flow is not recognized properly be the decompiler (that may be caused by the original code being very imaginative or the class has been compiled with a compiler that generates byte code not understood by the decompiler). I have experienced that my own code compiled with sun javac 6 would not decompile properly in one case with a nested while loop that had labels and breaks.
The class files may have also been obfuscated precisely to prevent decompilation.
In short, there's no guarantee a class file can be decompiled into valid java code, its not generally the decompilers fault, as one can express code flows in byte code that are impossible to express using plain java.
The generic way to (sort of) decompile such classes is to use javap (or any other tool that can display the byte code) and extract the logic by understanding the byte code yourself, then express the logic in plain java.
I have a Kitchen.jar file. I need to modify a class inside it. I decompile it with JD. Then I modify the Toster.java file and compile it with:
javac -classpath . Toster.java
And then I take it back into the Kitchen.jar with:
jar -uf Kitchen.jar Toster.class
All works except for one problem. When I open updated Kitchen.jar in JD I see that local variables inside all methods are renamed to something like localLongVar. Why?
The reason I ask is because Kitchen.jar refuses to work after the modification. And I suspect it has to be the compilation problem. Maybe I've misused some flags or anything. Not sure. I have no knowledge of Java whatsoever, except for the basic syntax.
My guess is that I compile it with latest 1.7 version and original jar is compiled with older JDK. That may explain failure of operation, but that doesn't explain the renaming of locals.
EXAMPLE
The random line from the original jar:
BigInteger[] result = new BigInteger[bis.length / 2];
And the very same line of my class:
BigInteger[] arrayOfBigInteger1 = new BigInteger[paramArrayOfBigInteger.length * 2];
So its result vs arrayOfBigInteger1.
By default javac removes debugging information other than source file and line number. Compile with javac -g or javac -g:vars.
From the documentation of javac
-g Generate all debugging information, including local variables. By default, only line number and source file information is generated.
-g:none Do not generate any debugging information.
-g:{keyword list} Generate only some kinds of debugging information, specified by a comma separated list of keywords. Valid keywords are:
source Source file debugging information
lines Line number debugging information
vars Local variable debugging information
The names of the variables are not preserved in compiled code. Most obvious to reduce the size of the compiled class. The compiler will replace them by shorter names. Doing this is also good for obfuscating the code so that someone who decompiles the code has problems to understand the logic. The localLongVar you see in JD is what the compiler makes of the replaced variable names.