How to add a code snippet to method body with JDT/AST - java

I'm trying to generate Java source code with JDT/AST. I now have MethodDeclaration and want to add a code snippet (from another source) to the method body. The code snippet can contain any Java code, even syntactically invalid code. I just can't find the way to do this.
With JCodeModel you would use JBlock#directStatement(String s) method.
Is there a way to do this with JDT/AST?

Since you have a well-formed tree for the rest of the application, and you want to insert non-well-formed text at a particular place, you pretty much can't do it with the standard tree node insertion mechanisms.
What matters is that you produce text for the valid program text with the fragment inserted in at at the right place. Somewhere in there must be a piece of logic that prints the AST as text. What you need to do is to ask that the AST be printed as text, and catch it in the middle of that process, at the precise point necessary, to insert your arbitrary text.
Our DMS Software Reengineering Toolkit has enter/exit print-node hooks in its prettyprinter to allow this kind of thing to happen.
If such things don't exist in JDT/AST, you can try to modify its prettyprinter to give you that hook. Alternatively, you might consider modifying JDT/AST by adding a another tree node type that isn't part of the standard set, that simply holds arbitrary text but acts like a method node. Presumably each node controls what is printed; then you could define the prettyprinting for that tree node, to cause it to output its text.
A final really hacky solution: insert a perfectly valid AST where the arbitrary text will go, containing somewhere a bogus identifier with a unique name, e.g., ZZZ. Then, print the AST to a string, and post-process the string to replace the bogus trees containing the unique name with the actual user text.

You first need to parse the code snippet into an AST. You can use the ASTParser API for this purpose.
It is possible to get the compilation problems of a compilation unit (See CompilationUnit.getProblems()).
There are a couple of ways to modify Java code using JDT. I'd suggest that you consider the ASTRewrite API for modifying the body of a method.

You can manipulate the AST with the ASTParser API - and the output doesn't even have to compile.
Here's an example for your case:
String textToInsert = "Some text";
StringLiteral stringLiteral = methodDeclaration.getAST().newStringLiteral();
rewriter.set(stringLiteral, StringLiteral.ESCAPED_VALUE_PROPERTY, textToInsert, null);
ListRewrite methodStatements = rewriter.getListRewrite(methodDeclaration.getBody(), Block.STATEMENTS_PROPERTY);
methodStatements.insertFirst(stringLiteral, null);
Result:
public void myMethod() {
Some text
}

Related

How can I get next available node in DOM with schema?

I need to query the names of "available" sub elements of an element node in DOM.
For example if schema says "There can be age, name, occupation elements under person element." then I wanna function like this,
import org.w3c.dom.Element;
Element person_element;
String[] names_of_available_sub_element =
get_available_sub_element_names(person_element);
which makes
names_of_available_sub_element == {"age", "name", "occupation"}.
How can I implement this function?
This isn't easy, but it can be done if you're prepared to put a lot of work in.
There are a number of approaches to getting information from an XSD schema. You could try and process the XSD source code, but I wouldn't recommend that, because there are so many things you have to take into account (wildcards, substitution groups, types derived by restriction and extension, and so on). A better approach is to use some kind of API that gives you access to the information in digested form. For that, some possible suggestions are:
(a) Xerces gives you a Java API providing programmatic access to the compiled schema.
(b) Saxon gives you two possibilities: (i) the SCM file, which is an XML representation of the compiled schema, and (ii) an XPath API giving programmatic access to the compiled schema using extension functions.
Do remember that knowing you're at a "person" element isn't (in the general case) enough to determine what the permitted children are. That's because there can be global and local elements using the name "person", but with different types. Whether this is a problem in your case depends on what you are trying to achieve, which you haven't really explained in much detail.

JavaParser: How to add new language elements

I want to create a Java transpiler that will read nearly-Java code (call it JavaHash) and emit "pure" Java code on the other end. In particular, I want to add a new token that is the hashtag "#" in front of a hashmap member so that I might access it similar to a JavaScript hash object:
Map<String, String> foo = new HashMap<String, String>();
...
foo.put("name", "Roger");
...
String name = #foo.name;
I can't get the JavaParser to do anything but throw an error on the "#" hashtag.
Are there ways to catch tokens before they are parsed?
This is very far from trivial, but doable.
JavaParser is based on JavaCC, it uses the following grammar to generate parser code. The parser then creates an abstract syntax tree using code model classes.
If you want to add new language elements, you will need to:
implement code model classes;
extend the grammar used for parser generation.
This is not so easy, you will need good knowledge and understanding of JavaCC. But it is absolutely doable.
The rest is peanuts. You'll write a visitor and use it to traverse the AST. Once you've encountered the node of the appropriate type, simply transform the part of AST into "normal" Java and serialize.
By the way, JavaParser is a very good basis to build something like what you want. So congratulations to your choice, this is half of the deal, actually.

Perform Linear Regression on data (from .arff file) - JAVA, Weka

I want to perform Linear Regression on a collection of data using Java. I have couple of questions..
what data types does linear regression method accept?
Because, I have tried to load the data in pure nominal format as well as numeric, but then when i'm trying to pass that 'data' (an Instance Variable created in program) to Linear Regression it gives me this exception. Cannot handle Multi-Valued nominal class
How to be able to print the Linear Regression output to console in java. I'm unable to produce the code to do so, after going through the predefined LinearRegression.java class, i got to know that buildClassifier() is the method that takes 'data' as input file. But then i'm unable to move forward. Can anyone help me understand the sequence of steps to follow to be able to get output to console.
protected static void useLinearRegression(Instances data) throws Exception{
BufferedReader reader = new BufferedReader(new FileReader("c:\somePath\healthCare.arff"));
Instances data = new Instances(reader);
data1.setClassIndex(data1.numAttributes() - 1);
LinearRegression2 rl=new LinearRegression2();
rl.buildClassifier(data); //What after this? or before
Linear Regression should accept both nominal and numeric data types. It is simply that the target class cannot be a nominal data type.
The Model's toString() method should be able to spit out the model (other classifier options may also be required depending on your needs), but if you are also after the predictions and summaries, you may also need an Evaluation object. There, you could use toSummaryString() or toMatrixString() to obtain some other statistics about the model that was generated.
Hope this Helps!

Parse a formula using ANTLR4

I am trying to parse a mathematical formula to a subset of LaTeX using ANTLR4. For example it should parse (a+4)/(b*10) to \frac{a+4}{b\cdot 10}.
My simple grammar creates a tree like this:
Now I am trying to implement parse tree listeners to somehow construct the LaTeX String while the tree is traversed. Here, I am failing because to construct a String like \frac{}{} it has to be built recursively. The parse tree walker, however, visits one tree node after the other (in a breadth-first way as far as I can tell).
I've read about parse tree visitors that might be what I need. But I wasn't able to find some examples how these visitors are applied.
Could you provide an example how parse tree listeners/visitors can be used in this particular case? Do you think my approach to use ANTLR for the parser makes sense in the first place?
You can create a parse tree walker by implementing the ParseTreeVisitor interface. For ease of use, you can specify Antlr to generate a base visitor when compiling the grammar (in Antlrworks, Run->Generate Recognizer->Next->Generate Visitor->Next->Finish). The base visitor will be called MyGrammarBaseVisitor. Note that the visitor has a generic type T, which every single visit method should return. I recommend using Void for manual manipulation or String for ease of use during code generation.
After you extend the base visitor (I'll assume here we're dealing with String), you need to override the visit methods. These methods are named after the grammar rules you have. Each of these methods will receive a ParserContext ctx parameter, which you use to visit child rules and/or get terminal values. For example, you could do this:
class MyVisitor extends MyGrammarBaseVisitor<String> {
#Override
public String visitMultiplicative(MyGrammarParser.MultiplicativeContext ctx) {
if (ctx.opMult().getText().equals("/")) return "\\frac{" + visit(ctx.expr(0)) + "}{" + visit(ctx.expr(1)) + "}";
else return visit(ctx.expr(0)) + "\\cdot " + visit(ctx.expr(1));
}
// visit methods for other rules...
}
I'm assuming your multiplicative rule looks like multiplicative: expr opMult expr; opMult: '*' | '/'; You can find more information in The Definitive Antlr 4 Reference. You may also find more information and examples in the Antlr documentation.

Performance-effective way to transform XML data represented as Writeable

I'm working on utility method that allows conversion of XML data into formatted String and before you're going to think it's a trivial task for javax.xml.transform.Transformer let me explain the specific constraints I've faced with.
The input data does not exist at the moment conversion starts. Actually it's represented as groovy.lang.Writeable (javadoc) instance that I could output into any java.io.Writer instance. Signature of method looks like this:
static String serializeToString(Writable source)
My current solution involves few steps and actually provides expected result:
Create StringWriter, output source there and convert to String
Create javax.xml.transform.stream.StreamSource instance based on this string (using StringReader)
Create new StringWriter instance and wrap it into javax.xml.transform.stream.StreamResult
Perform transformation using instance of javax.xml.transform.Transformer
Convert StringWriter to String
While solution does work I'm not pleased enough with its efficiency. This method will be used really often and I do want to optimize it. What I'd like to avoid is necessity to perform multiple conversions along the line:
From Writeable to String (unformatted)
From String to StreamSource (which means that data will be parsed again)
From StreamSource to String again (formatted)
So the question is whether it's possible to build pipe-like flow which eliminates unnecessary conversions?
UPDATE #1:
To give a little bit more context, I'm converting GPathResult instance to formatted string using StreamingMarkupBuilder.bindNode() method which produces Writable instance. Unfortunately there is no way to specify StreamingMarkupBuilder to produce formatted output.
UPDATE #2:
I did experiment with implementation based on PipedWriter + PipedReader but experiments didn't show much speed gain from this approach. Looks like it's not that critical issue in this case.
Not knowing what you mean exactly by "XML data", but you could think of representing the "Yet-to-be" stuff as a SAXSource directly, thereby by-passing the "to-string" and "parse-string" steps.

Categories