JavaParser: How to add new language elements - java

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.

Related

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.

transform Scala case class to org.apache.solr.common.SolrInputDocument

Are there any generic implementations out-there which can transform a Scala case class to SolrDocument ?
Since I could not find any such mapper utility that I can reuse, I took the below approach:
Create the case class object
Get non-empty fields by transforming case class object to Map
Add fields to the mutable document one-by-one.
This approach works for me, but I would have to create the intermediate Map object. I want to avoid this for verbosity and complexity reasons. Is there a better way of doing it?
Not a complete answer (I would write this in a comment, but need a few more rep), but just you point you in a direction, macros are the way to do this in a type-safe way without writing boiler plate mapping functions for every case class. JSON libraries deal with the same problem (except replace SolrDocument with JSON object). As an example you can take a look at the JSON serializer/deserializer macro implementation from Play Framework:
https://github.com/playframework/playframework/blob/master/framework/src/play-json/src/main/scala/play/api/libs/json/JsMacroImpl.scala
I suspect this solution is a little more heavy than you were looking for. The way I would approach it is to write the stupid boilerplate mapping functions for each case class, and only go down the macro path if this becomes a significant burden.
Seems fairly trivial to modify one of these answers:
def getSolrDoc(cc: Product): SolrDocument = {
val solrDoc = new SolrDocument
cc.getClass.getDeclaredFields.foreach { f =>
f.setAccessible(true)
solrDoc.addField(f.getName, f.get(cc))
}
solrDoc
}
And usage:
case class X(a:Int, b:String)
val x = X(1, "Test")
val doc = getSolrDoc(x)
println(doc) // prints SolrDocument{a=1, b=Test}

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

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
}

How to avoid a large if-else statement in Java

I'm developing a framework in java which relies on a number of XML files with large number of parameters.
When reading the parameters from the XML file, I have to have a large if-else statement to decide what the parameters is and then call appropriate methods.
Is this normal? to have a large if-else statement?
I am thinking that there is a simple and neater way of doing this, e.g. Java XML mapping or Java Reflections? is this the answer? if so, can you please provide examples of how this is done so I don't have to rely on a large if-else statement?
Thanks!
You want to first create an interface:
public interface XMLParameterHandler {
public handle_parameter (String XMLData);
}
Next you want to create a map:
private Map<string, XMLParameterHandler> handlers;
...and initialize it with one of the relevant Map implementations:
this.handlers = new HashMap<>();
You need to implement the interface on a number of classes, one for each parameter you intend to handle. This is a good use of inner classes. Insert each of these implemented handerls into the map:
handlers.put ("Param1", new XMLParam1HandlerImpl());
handlers.put ("Param2", new XMLParam2HandlerImpl());
Then you can call the handler from the xml processing loop:
handlers.get (paramValue).handle_parameter(XmlData);
There is JAXB (http://en.wikipedia.org/wiki/Java_Architecture_for_XML_Binding) for mapping java class to xml.
But you can't map methods with it: you only can map attributes to xml file values (deserialize parameters from xml).
i recommend to use Map, that have parameter as key and xml entry as value(not whole xml)
Reflection would be one approach. Perhaps combined with a custom annotation on the target method to indicate which parameter to pass to that method. This is an advanced technique, though.
A more standard technique would be to use a map, where the key is the attribute name, and the value is an instance of an implementation of some interface you define, like AttributeHandler. The implementations then contain the code for each attribute. This involves writing a lot of little classes, but you can do them as anonymous classes to save space and keep the code inline.
a large if-else statement to decide what the parameters is and then call appropriate methods
You could instead use the Strategy design pattern, with one Strategy object per parameter, and use a map from the parameter name to the Strategy object to use. I've found this approach useful for even a moderately complicated application of XML.
It sounds to me as if you want a data-driven rule-based approach to writing your application, rather like you get in XSLT. One way of achieving this is to write it in XSLT instead of Java - XSLT, after all, was specifically designed for processing XML, while Java wasn't. If you can't do that, you could study how XSLT does it using rules and actions, and emulate this design in your Java code.
N functions with M parameters can always be implemented with a single function with M + 1 parameters.
If you need a big if then else statement to decide which method to dispatch to, then you can just add a parameter to your method and call a single method.
You shouldn't need an if-then-else statement to bind the parameter values.
If there is complex logic dependent on the particular parameter values, you might use a table driven approach. You can map various combinations of paramemter values into equivalence classes, then variouos equivalence class combinations into a row in a table with a unique id, then have a switch statement based on that unique id.

Json Deep serialize

In a case where Person is a POJO having a List of "hobbies".
Just trying to understand this statement to implement a deep serialize mechanism:
new JSONSerializer().include("hobbies").serialize( person );
Does the syntax seem intuitive? From a java user POV, it seems the syntax should be:
new JSONSerializer().serialize( person ).include("hobbies");
I say this because it seems intuitive first to serialize the priamry object and then any Lists, references thereof.
Also, is the source code of flexjson available for public use? It is not present on sourceforge.net
You cannot do the latter so easily - the implementation would not know when you are done. You need to have some kind of terminator that performs the action, such as as .run() or .done()..

Categories