2.5.1 to 3.0.0 migration guide
Instantiating nodes
Many methods have been added that help with building AST nodes. To help reuse, most of them are methods on interface called “NodeWith…” The suggested way to instantiate a node is …
- with a builder method on the parent (like
CompilationUnit#addClass(String name)
) - if that doesn’t exist, with a specific constructor for your case (like
ThrowStmt(Expression expression)
) - if that doesn’t exist, the default constructor…. and use the setters to finish setting up your new node. Note that the setters return “this”, so you can chain them.
- alternatively, you can use the
JavaParser.parse
methods to quickly construct a partial Node from a snippet of code.
The new API
The API has been thoroughly cleaned up.
The quick API
The most straightforward API is to use the static methods on JavaParser. We have attempted to simplify exception handling, so that any problems are reported with an unchecked ParseProblemException. All of the static methods are shortcuts to the full API, which you get when you instantiate JavaParser.
The full API
When you want to have full flexibility and a little speed up, use the full API, which means calling “parse” on an instance of JavaParser
. This API does not throw exceptions, it will collect all encountered problems in a list. For 3.0.0, this list will often contain only a single problem, but in the future the parser will be able to recover from a parse problem to report multiple parse problem.
ParserConfiguration configuration = new ParserConfiguration();
JavaParser parser = new JavaParser(configuration);
// ParseStart gives flexibility for what you want to parse
// Providers gives you many ways to provide source code.
ParseResult<Expression> parseResult = parser.parse(ParseStart.EXPRESSION, Providers.provider("1+1"));
if (!parseResult.isSuccessful()) {
System.out.println(parseResult.getProblems().toString());
}
// a failed parse does not always mean there is no result.
if (parseResult.getResult().isPresent()) {
Expression expression = parseResult.getResult().get();
System.out.println(expression);
}
if (parseResult.getCommentsCollection().isPresent()) {
// ...
}
if (parseResult.getTokens().isPresent()) {
// ...
}
Repeatedly parsing with a single instance should perform better.
ASTHelper
The ASTHelper class has been removed. Its methods are now among the many “builder” methods that can be found in the nodes themselves. Example: if you are looking for ASTHelper.addStmt(BlockStmt block, Expression expr)
, you should look in BlockStmt#addStatement(Expression expr)
.
InstanceParser
This class has been removed. Simply create an instance of JavaParser for the same effect: new JavaParser()
Array support changes
Probably the biggest change is in how we support arrays. Where previously arrays were indicated by an inconspicuous integer telling you how many brackets there were, they are now in your face: every type that can have array dimensions may now be nested in ArrayType
.
You will notice that for a declaration like int a;
, there is no more getType(). This has moved to the VariableDeclarator for a
. Why? Because in int a[], b;
the types of a and b are different: a = ArrayType(int) and b = int. Therefore we cannot talk about the type of the whole declaration anymore. This will unfortunately make dealing with types a bit more complex, but we gain correctness (no more forgetting about that integer that indicates that there is a bracket pair in int a()[] {}
) and a more consistent API.
ReferenceType
Where 2.5.1 created a reference type by instantiating “ReferenceType”, then setting the type to refer to, this has now been simplified by simply making all reference types (ClassOrInterfaceType etc.) inherit from ReferenceType. No need for this indirection anymore.
(User) Data
The Node#data field has become more structured. We copied it from Wicket, including their Javadoc, so it should be clear :-)
TypeArguments
TypeArguments was a bit of an odd type, a list that stored an extra field. It has been mostly merged into the nodes that have type arguments, using the interface NodeWithTypeArguments
, so the data you’re looking for is not far away.
Nulls
We now deal very strictly with nulls:
- Any method that used to return nulls now returns an Optional.
- Any method that does not return Optional never returns null.
- Any parameter that takes nulls still does.
- Any parameter that does not take nulls will throw an AssertionError when you pass it a null.
NodeList
To avoid some issues with setting the parents of nodes, we have introduced NodeList. It behaves like a Java List, but takes care of setting the parent of nodes that you add.
DumpVisitor
DumpVisitor has been upgraded to “PrettyPrinterVisitor.” It has its own package and some support classes now. PrettyPrinter is the suggested class to use to access it.
Names in the AST
Everything that has a name now uses SimpleName or Name. This makes names first class citizens in the AST. To reduce noise, you can find many shortcuts that use Strings. Methods called “…asString()” have been added that intend to return the node as a clean string, without comments or whitespace. (Remember that toString() uses the pretty printer and should not be used in comparisons etc.)
Node naming
Many nodes and fields have been renamed for consistency.
Observables
All nodes can be observed now, which makes it easier to build tools that need to track changes that are made to the AST.
Empty….
We are slowly phasing out “Empty…” nodes, since these are just placeholders for meaningless constructs, mostly stray semi-colons.
VariableDeclaratorId
VariableDeclaratorId became a wrapper for a SimpleName when we moved array information around, so from now on we’re using SimpleName name
instead of VariableDeclaratorId id