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.
Related
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.
I am trying to read a common SMTLib2 file by the Java API of Z3 using the following method:
BoolExpr parseSMTLIB2String (String str, Symbol[] sortNames, Sort[] sorts, Symbol[] declNames, FuncDecl[] decls)
The issue is that it seems that it only reads the assertions and ignores the rest. So one cannot add a new assertion based on a sort that is defined in the file. The sort is unknown and the addition of the assertion fails.
Is there any way to do this that I miss?
If not, it seems that I should directly generate SMTLib2 format instead of using the API.
Thanks for your consideration.
That's correct, this function returns one expression that is the conjunction of all assertions in the file, ignoring (almost) all other file content. There is no function for reading SMT2 commands as that is usually done outside of Z3.
That said, parseSMTLIB2String takes the parameter sorts, which can be populated by sorts later referred to in the SMT2 file. This can be used such that the SMT2 file and the rest of your infrastructure refer to the same sorts.
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.
I have an app that gets the content of an html file.
Lets say the text of the page is:
String[] arr = new String[] {"!","#","#"};
for (String str : arr) {
write(str);
}
Can I somehow compile this text and run the code within my app?
Thanks
Use Janino. It's a java runtime in-memory compiler. Way easier than BCEL and the likes.
From the homepage:
"What is Janino?
Janino is a super-small, super-fast Java™ compiler. Not only can it compile a set of source files to a set of class files like the JAVAC tool, but also can it compile a Java™ expression, block, class body or source file in memory, load the bytecode and execute it directly in the same JVM. Janino is not intended to be a development tool, but an embedded compiler for run-time compilation purposes...
You can use the javac compiler, or the Java Compiler API or the BeanShell library (or similar). You can compile it any number of ways, none terribly simple which often leads to finding another way to solve your problem.
Instead of generating source and compiling its common to generate byte code directly using ASM, Javaassist, BCEL or the like
This appears to be the same as
for(char ch: "!##".toCharArray())
write(ch);
which is likely to be the same as
write("!##");
Since the question is tagged android:
The answers posted so far only apply to the “standard” JVM, not to Android's Dalvik VM. In principle, it is possible on Android too. I don't know if there's an existing Java compiler that you can embed, but you would probably generate the final Dalvik bytecode using dexmaker. It may be possible to combine an existing Java compiler with dexmaker.
But please think twice before attempting anything like this, and be very careful. The last thing you want is a way for an attacker to execute arbitrary code on your user's hardware.
You can try javassist, it's not full Java though.
This is not usually that hard to do, but I have to ask can you give more detail on exactly what it is you are trying to accomplish. I do this type thing all the time. This is just another example of getting information from the user and using it somewhere else in your code. Since your using java maybe look at the string API http://docs.oracle.com/javase/6/docs/api/java/lang/String.html and the string tokenizer http://docs.oracle.com/javase/6/docs/api/index.html?java/lang/package-summary.html
Now you can break the string down into single values one word or other value at a time. From there you can use functions such as isNAN() from the float or double class to determine if it a number or string or whatever it is your testing for. Now you know what you’re dealing with you can reconstructed the data in a usable form.
Note for values if you want to use them as values use Float(string value) constructor. i.e Float x = new Float(myString)
I have a parser written in bigloo scheme functional language which I need to compile into a java class. The whole of the parser is written as a single function. Unfortunately this is causing the JVM compiler to throw a "Method too large" warning and later give "far label in localvar" error. Is there any possible way where I can circumvent this error? I read somewhere about a DontCompileHugeMethods option, does it work? Splitting the function doesnt seem to be a viable option to me :( !!
Is there any possible way where I can circumvent this error?
Well, the root cause of this compiler error is that there are hard limits in the format of bytecode files. In this case, the problem is that a single method can consist of at most 65536 bytes of bytecodes. (See the JVM spec).
The only workaround is to split the method.
Split the method in related operations or splitting utilities separately.
Well, the case is a bit different
here, the method only consists of a
single function call. Now this
function has a huge parameter list(the
whole of the parser actually!!). So I
have no clues how to split this!!
The way to split up such a beast could be:
define data holder objects for your parameters (put sets of parameters in objects according to the ontology of your data model),
build those data holder objects in their own context
pass the parameter objects to the function
Quick and Dirty: Assign all your parameters to class variables of the same name (you must rename your parameters) at the beginning of your function and start chopping up your function in pieces and put those pieces in functions. This should guarantee that your function will basically operate with the same semantics.
But, this will not lead to pretty code!