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.
Related
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.
Why does the Java byte-code interpreter change a 'class' file when I change only symbol names (classes, interfaces, functions or variables) in the corresponding 'java' file?
I am maintaining both types under source control (GIT), and I keep seeing "twice the amount of changed files" even for cosmetic changes such as the one mentioned above.
BTW, the question is not on source-control issues, but just FYI, the reason I keep these files on GIT is in order to be able to do "clean up" (delete all unversioned files), and then run the program from a command-line without recompiling it.
If you have any idea how to achieve this functionality (run without build) otherwise, then I would be happy to hear it...
Thanks
Because the class files contain the symbol names.
Generally, people do not keep their class files in source control. If someone wants an old version of a class file, they get the old source file and compile it.
The JVM needs access to the symbol names, for a number of reasons, including the following.
The JVM uses symbol names to find classes, methods and so on.
The presence of symbol names enables us to write code that uses reflection.
Symbol names appear in stack traces when an exception is thrown.
So the symbol names need to be stored in the class path.
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.
When you compile your java files, does it also embed your javadocs and comments into the class file?
For example, if you have large javadocs, does it effect the overall size of your class file? Or does the compiler ignore everything beginning with // and /* ?
No, comments are not compiled into your class files. This includes JavaDocs.
Instead, you need to use a JavaDoc tool (like Sun/Oracle's) on the source code to generate the documentation.
No, the class file is just binary data.
Annotations may be retained (depending on the annotation).
Comments won't affect the size of the class file.
No. There are several debug options that affect the size of a class file but the comments are never part of the resulting .class file.
Some estimate:
-g:line just adds line number information (a few bytes)
-g:vars includes the full names of all variables. This is usually the most expensive option.
-g:source just adds the name of the source file (without path).
Note: -parameters makes names of method parameter accessible via reflection. This is independent of -g:vars.
Comments (and therefore JavaDoc) are never added to the bytecode.
To see what ends up in the .class file, use javap -v plus the path of the file.
I am creating an eclipse plugin, and I need Class object of selected file, not IType. Is it possible, and how is the best way to do it?
Edit: when I think about it, the best way is to add it like run as (like junit, profiler, or other plugins are doing). I suppose they must have access to Class (if X is class in question), because they are running it's functions. So how to create plugin that has "run as " action, and get live object?
In an eclipse plugin, you will, for instance, get the selected file through an IAction.
(it represents the non-UI side of a command which can be triggered by the end user. Actions are typically associated with buttons, menu items, and items in tool bars.)
From there:
IResource selectedResource = ResourceUtils.getSelectedResource();
IResource The workspace analog of file system files and directories. There are exactly four types of resource: files, folders, projects and the workspace root.
From its type, you can cast it into an IFile, which gives you acces to its full path (getFullPath())
Eclipse uses an abstract representation of the object being selected, be it a file (IResource) or be it a Java Type (IJavaType). As it is not required for a source file to be compiled (e.g. disabling auto build), there does not necessarily be a .class file or a Class object for the code being edited. Hence, there is no correct way to get a "Class" object from the a selection in the user interface.
However, as yesterday mentions, you could rely on the fact that the Eclipse builder mechanism will always compile the source files immediately and thus a .class file exists. To reach to this .class file at runtime, you would need to create a dynamic class loader for the project or start a runtime VM. I tried that and it does work, but it is a very unstable approach and can lead to various hard to trace failures.
The classname of an IType "curIType" can be retrieved through
curIType.getFullyQualifiedName()
That's the simple part. But then you have the problem, that this class does not have to be in the classloader of your plugin (if it's a class of one of the userprojects, it's seldom part of your classloader). So calling Class.forName(classname) won't do any good.
I had a similar case and did (in a first attempt) solve it by creating an own thread with an own classloader, which included all libraries of the current classloader and all libraries of the type's project. That's neither a short code nor a simple one and I've already refactored it. It's much simpler to get all information out of the IType and not using the classes anywhere in the plugincode.