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
Related
I'm trying to get the line number of annotations from .class file, but I can get only the list of annotations, not the lines. Is it possible to do this?
Looking through the Java Class File Specification it seems that for annotations no line number information is recorded.
Since the line number information is not present within the class file you cannot extract it from the class file.
Line numbers are only available for code segments: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.12
You can use Java Decompiler. Follow this JD GUI, download the jar file and run it, keep the class files you want to decompile in same place with the jd-gui jar's directory and you will find if any annotation is used in source code there.
I am trying to make it easy for my non-developers to locate certain exceptions in my code and so I want to figure out if there is a way I can have maven search through my source as it is being built, pick out these specific exceptions and add them with the source code file name and line number to a separate file. For instance this code:
throw new MyException("1234-ABCDEF-1234-CDEF45");
would add an entry in a file in the JAR when I compiled that would look like this:
1234-ABCDEF-1234-CDEF45,com\me\test\MyJavaFile.java,267
With that information, if my support staff has "1234-ABCDEF-1234-CDEF45" as an error they could cross reference that value in the file and know the file/line number. BTW I understand that printing the stack trace to the log would also give them this information, but I am purposely not printing the stack trace to the log file because these happen a lot and are excepted in the normal flow of the program.
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 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.
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.