I have faced some difficulties with Java parsing. I need somehow to get comments of class, fields, methods etc. via reflection.
I have found JavaParser and it looks like it can elicit comments but I haven't got how to do it as all the examples just parse given string. I have found TypeSolver that can take Canonical name but it looks like that it can't work with comments.
My question is how to find comments if I have only Class<?> and also the project has some other jar's that should also be introspected. Via debugging I see the original source code and it looks like that it is possible to do somehow.
Thanks.
P.S. I have source code, I need to match Class<?> with source code and then extract comments via JavaParser
First of all, you cannot directly get comments using reflection, and you cannot get them by using a library that reads the ".class" file. The information is not present the ".class" file, and reflection only knows about information is directly available from there.
As people have pointed out, you can only get comments if you have the source code. And if you have a source code file you should be able to extract comments using JavaParser or (possibly) some other library, ... or by writing your own parser.
The problem will be mapping from a Class object to the corresponding source code file. Let us assume that you have multiple source trees corresponding to multiple JARs on the application's classpath. You will need:
the URIs for each JAR or directory on the classpath,
a mapping from each URI to a corresponding source tree.
The approach would be:
Get the fully qualified class name from the Class object.
Map the classname to a relative Java source path; e.g. foo.bar.Baz would become foo/bar/Baz.java
Use clazz.getProtectionDomain().getCodeSource().getLocation().toURI() to get the URI from whence the class was loaded.
Map the URI to the corresponding source tree ... using your mappings.
Resolve the relative path relative to the root of the source tree.
Open the source file.
Some of the above steps could present problems. For example:
in step 2, you need to deal with nested classes,
in step 3, getCodeSource() could return null,
in step 3, the resulting URI could have a weird protocol,
if your mapping are incomplete, step 4 could fail,
if your source code doesn't match the code you are executing, step 5 could fail.
Once you have the source file open, you construct a Reader and parse the source code ... using your chosen Java parser.
If yours was a "green field" project, it may be simpler to define a custom annotation type (with retention runtime) and turn your comments into annotations. These annotations can be extracted simply and quickly, with none of the possible failure modes in the above.
But the flipside is that annotations are cumbersome to write (in the source code) compared to comments. Also, you would be bloating the ".class" files with the extra annotations.
I haven't got how to do it as all the [JavaParser] examples just parse given string.
The javadoc shows that you can use a JavaParser instance to parse a File, an InputStream, a Reader or a String.
I doubt that comments are contained in compiled code - so there is no way to do it by reflection. Closest tool to do it would be XDoclet-1/2 which parsed javadoc tags and used them to generate other stuff (and this inspired annotations) - but this tool is obsolete and not suppported anymore
If you have the source code, it is probably in form of a JAR file. It is quite easy to locate the source file in the JAR file as the class provides both the package as well as local name. You have to consider a case with nested classes, but its is actually quite easy to implement.
When you've located the source file, you can easily parse it with JavaParser and retrieve the comments:
String classText = "public class Dummy{\n" + "//Comment\n" + "}";
StringReader reader = new StringReader(classText);
CompilationUnit compilationUnit = JavaParser.parse(reader, true);
for (Comment comment : compilationUnit.getAllContainedComments()) {
System.out.println(comment.getContent());
}
You can't.
Bytecode does not contain any comments, either inline or in JavaDoc format, from the original source code, as they are removed during the compilation phase.
If you need the comments to somehow be transferred into the Bytecode, consider using Java's Annotations instead.
Related
ANTRLR newbie question. Say for a given grammar ANTLR maven plugin has created all the necessary Java classes to traverse and parse a text. And it works just fine when used as prescribed in "The Definitive ANTLR4 Reference".
Now imagine I need to reuse the generated classes to parse an expression which is defined by a rule buried somewhere deep in the grammar file.
However the Reference doesn't seem to provide a clue as to how to select a specific rule as a starting one, the generated classes always expect the whole grammar tree being present in the source.
Using the generated classes as-is doesn't work either, cause the corresponding listener and parser methods expect a context parameter which can only be created when having a "parent context" and an "invoking state" which I don't know how to define.
The only (and rubbish) solution I came up with so far, is splitting the grammar into two files so that the low-level rule in question would become top-level one, and import the latter into the first.
Do I miss something obvious here? Any help would be appreciated.
This is very simple. Load your input stream with the text that you wanna match against one of the subrules, then call the function for that subrule in the parser as you did with the main rule. Each grammar rule is represented by a function, which you can simply call for your subtext and it will generate a stripped down parse tree then, which applies only to this subrule (and it's children).
Im looking for a parser that could parse .java file and create some object, which should held informations about this file's methods, attributes. classes, interfaces, methods parameters and annotations.
Do you know any?
I found https://code.google.com/p/javaparser/, but im not sure if it can handle annotations, which are important for me..
any advice?
thanks
Why not use the standard Java Compiler API? I know it was discussed within the latest Java Magazine issue -- for some source samples, see here.
You could use the Java Grammar (http://docs.oracle.com/javase/specs/jls/se7/html/jls-18.html) and use a parser generator (for example YACC) or Scala ParserCombinators to generate an AST. In this grammar, annotations are contained.
I am using JavaParser to parse java Code, and yes - it can handle annotations, for example - getting method's annotations:
List<AnnotationExpr> annotations = method.getAnnotations();
Adding annotations (by name) to a method:
annotations.add(new NormalAnnotationExpr( ASTHelper.createNameExpr("Override"), null));
How to get the variables name declared within a method in java class?
for eg:
public class A {
String x;
public void xyz(){
int i;
String z = null;
//some code here
}
Method[] methods = A.class.getDeclaredMethods();
for (Method q = methods){
//some code here to get the variables declared inside method (i.e q)
}
}
How can i do that?
Thanks in advance..
There is no simple way to do this.
If those were fields, you could get their names using reflection. However, local variable and parameter names are not loaded into the JVM. So you would need to resort to reading the "A.class" file and extracting the debug information for that method. And the bad news is that if the class wasn't compiled with debug information, then even that wouldn't work.
There are libraries around for reading ".class" files for various purposes, but I can't give a specific recommendation.
But the $64,000 question is "But why ...?". What is the point of listing the local variable names for a method from Java? Can't you just look at the source code? Can't you dump the ".class" file with "javap" or decompile it with some 3rd party decompiler?
I thought for big programs it will be useful to understand and analyze it if we can come to know the variables their types and method names and their parameter list etc so only...
I think you just need a decent IDE ...
To paraphrase another answer, There's no simple way to do this with reflection.
There is a way to do it. You need a full Java source code parser and name/type resolver ("symbol tables").
The Java compiler offers internal APIs to get at that information. Eclipse JDT offers something similar. Our DMS Software Reengineering Toolkit offers a full parser with this information easily accessible, and considerable additional help to build analyzers and/or code generators that take advantage of this extra information. (You can see this information extracted by DMS in the example Java Source Code Browser at my site, see bio).
i would like to analyse my code, classes and methods : my goal is to create a sequence diagram by reversing my code
But , i would like to analyse it without running the application
So, i already get my classes and methods names
What i am looking for now , is to read/get the content of a method , without using a regex expression to parse my entire file
Is there a simple way to get it ?
Thanks
I think you can use Groovy's Global AST Transforms to analyze your code. It will give you access to the abstract syntax tree. From there you can walk in the tree nodes of your code. This is 'hooking' in the Groovy compilation process.
I'm not sure it will work with Java code. Java is Groovy code, so in theory it could work, but the compiler won't go through .java files.
Is there any way to override the line numbers in Java (e.g., by using some kind of preprocessor directive)?
I am "compiling" a high-level language, down to Java byte code using Janino. I need compiler errors to report the line from the original file, not the generated Java code.
C# has the #line directive, and I've successfully exploited it to map line numbers from a source file to the compiled result. I need the same for Java.
Thanks!
I've never seen it used for other than JSP, but JSR-45 was designed to be used for this purpose for any source language. The process involves creating a second file in a special format ("SMAP") that maps line numbers in the original source to line numbers in the generated Java source code.
Unfortunately, no, there isn't an equivalent #line directive in Java. The best you can do is modify the source after it's been generated by deleting/inserting newlines to match the real source (or modify the code generator). Or, you could modify the line numbers stored in the binary class files after they've been compiled, but that will likely be even more painful.
Using Janino you can derive from Scanner and override the location() method. This method returns a Location object. You can override the read() method to look for annotations, within comments for instance (added during code generation), that hold line number information.
You simply pass your scanner to the SimpleCompiler.cook() method and you can control what filename, line and column get reported on error.
Instead of generating Java code as your intermediate language, you could try using JVM assembler. Jasmin has nice syntax, and you are free to insert .line directives at appropriate places in your code. You can also can also specify the original source file using the the .source directive.
Granted, going the assembler route may be more hassle than it's worth :)
There is no simple solution. One workaround would be to generate a line number map from [your language] to Java when you generate the code. You can pipe the compiler output and use the map to replace Java's line numbers with your line numbers.