Preserving commit history am: b7e221621d am: 7d05f42406
am: ac95818199

Change-Id: I03d7d631ac4c2f0dec9704ce6c73d3f6230dab29
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..16db129
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,44 @@
+/lib
+bin
+.manager
+target
+.settings
+*~
+.project
+.classpath
+release.properties
+**/.DS_Store
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+.gradle
+build-*
+*.asc
+build
+out
+.java-version
+
+
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/dictionaries
+
+# Sensitive or high-churn files:
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.xml
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+
+# Gradle:
+.idea/**/gradle.xml
+.idea/**/libraries
+
+*.iws
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..eac2ad1
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+javaparser-parent
\ No newline at end of file
diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml
new file mode 100644
index 0000000..d7c1d0e
--- /dev/null
+++ b/.idea/codeStyleSettings.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectCodeStyleSettingsManager">
+    <option name="PER_PROJECT_SETTINGS">
+      <value />
+    </option>
+    <option name="PREFERRED_PROJECT_CODE_STYLE" value="JavaParser" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..0aebde2
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+<component name="ProjectCodeStyleConfiguration">
+  <state>
+    <option name="PREFERRED_PROJECT_CODE_STYLE" value="JavaParser" />
+  </state>
+</component>
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..a785d8b
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <annotationProcessing>
+      <profile name="Maven default annotation processors profile" enabled="true">
+        <sourceOutputDir name="target/generated-sources/annotations" />
+        <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
+        <outputRelativeToContentRoot value="true" />
+        <module name="javaparser-core" />
+        <module name="javaparser-core-generators" />
+        <module name="javaparser-metamodel-generator" />
+        <module name="javaparser-symbol-solver-core" />
+        <module name="javaparser-symbol-solver-logic" />
+        <module name="javaparser-symbol-solver-model" />
+        <module name="javaparser-symbol-solver-testing" />
+        <module name="javaparser-testing" />
+      </profile>
+    </annotationProcessing>
+    <bytecodeTargetLevel>
+      <module name="javaparser-core" target="1.8" />
+      <module name="javaparser-core-generators" target="1.8" />
+      <module name="javaparser-metamodel-generator" target="1.8" />
+      <module name="javaparser-parent" target="1.8" />
+      <module name="javaparser-symbol-solver-core" target="1.8" />
+      <module name="javaparser-symbol-solver-logic" target="1.8" />
+      <module name="javaparser-symbol-solver-model" target="1.8" />
+      <module name="javaparser-symbol-solver-testing" target="1.8" />
+      <module name="javaparser-testing" target="1.8" />
+    </bytecodeTargetLevel>
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..4d6b457
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding">
+    <file url="file://$PROJECT_DIR$" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/javaparser-core" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/javaparser-core-generators" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/javaparser-metamodel-generator" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/javaparser-symbol-solver-core" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/javaparser-symbol-solver-logic" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/javaparser-symbol-solver-model" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/javaparser-symbol-solver-testing" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/javaparser-testing" charset="UTF-8" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..146ab09
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,10 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
+      <option name="processCode" value="true" />
+      <option name="processLiterals" value="true" />
+      <option name="processComments" value="true" />
+    </inspection_tool>
+  </profile>
+</component>
\ No newline at end of file
diff --git a/.idea/markdown-doclet.xml b/.idea/markdown-doclet.xml
new file mode 100644
index 0000000..d7bd314
--- /dev/null
+++ b/.idea/markdown-doclet.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ch.raffael.mddoclet.integrations.idea.MarkdownDocletIdea.ProjectConfiguration">
+    <option name="enabled" value="true" />
+    <option name="renderingOptions">
+      <RenderingOptions />
+    </option>
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..68010fc
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="EntryPointsManager">
+    <list size="4">
+      <item index="0" class="java.lang.String" itemvalue="com.github.javaparser.metamodel.DerivedProperty" />
+      <item index="1" class="java.lang.String" itemvalue="org.jbehave.core.annotations.Given" />
+      <item index="2" class="java.lang.String" itemvalue="org.jbehave.core.annotations.Then" />
+      <item index="3" class="java.lang.String" itemvalue="org.jbehave.core.annotations.When" />
+    </list>
+  </component>
+  <component name="MavenProjectsManager">
+    <option name="originalFiles">
+      <list>
+        <option value="$PROJECT_DIR$/pom.xml" />
+      </list>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" project-jdk-name="1.8" project-jdk-type="JavaSDK" />
+</project>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..1a08e14
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/javaparser-core/javaparser-core.iml" filepath="$PROJECT_DIR$/javaparser-core/javaparser-core.iml" />
+      <module fileurl="file://$PROJECT_DIR$/javaparser-core-generators/javaparser-core-generators.iml" filepath="$PROJECT_DIR$/javaparser-core-generators/javaparser-core-generators.iml" />
+      <module fileurl="file://$PROJECT_DIR$/javaparser-metamodel-generator/javaparser-metamodel-generator.iml" filepath="$PROJECT_DIR$/javaparser-metamodel-generator/javaparser-metamodel-generator.iml" />
+      <module fileurl="file://$PROJECT_DIR$/javaparser-parent.iml" filepath="$PROJECT_DIR$/javaparser-parent.iml" />
+      <module fileurl="file://$PROJECT_DIR$/javaparser-symbol-solver-core/javaparser-symbol-solver-core.iml" filepath="$PROJECT_DIR$/javaparser-symbol-solver-core/javaparser-symbol-solver-core.iml" />
+      <module fileurl="file://$PROJECT_DIR$/javaparser-symbol-solver-logic/javaparser-symbol-solver-logic.iml" filepath="$PROJECT_DIR$/javaparser-symbol-solver-logic/javaparser-symbol-solver-logic.iml" />
+      <module fileurl="file://$PROJECT_DIR$/javaparser-symbol-solver-model/javaparser-symbol-solver-model.iml" filepath="$PROJECT_DIR$/javaparser-symbol-solver-model/javaparser-symbol-solver-model.iml" />
+      <module fileurl="file://$PROJECT_DIR$/javaparser-symbol-solver-testing/javaparser-symbol-solver-testing.iml" filepath="$PROJECT_DIR$/javaparser-symbol-solver-testing/javaparser-symbol-solver-testing.iml" />
+      <module fileurl="file://$PROJECT_DIR$/javaparser-testing/javaparser-testing.iml" filepath="$PROJECT_DIR$/javaparser-testing/javaparser-testing.iml" />
+    </modules>
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..640d3ae
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,16 @@
+sudo: false
+language: java
+install: mvn install -DskipTests=true
+script: mvn test
+jdk:
+  - oraclejdk8
+  - oraclejdk9
+notifications:
+  webhooks:
+    urls:
+      - "https://webhooks.gitter.im/e/ec3127975d8a2b8f11d0"
+    on_success: always  # options: [always|never|change] default: always
+    on_failure: always  # options: [always|never|change] default: always
+after_success:
+  - mvn test jacoco:report coveralls:report
+# http://lint.travis-ci.org/ validator
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..829165e
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,30 @@
+## Getting started
+Here is some information that's good to know when contributing to JavaParser:
+
+- There is some interesting information on the [wiki](https://github.com/javaparser/javaparser/wiki).
+- We work on JavaParser because we like to, not because it earns us money. Please remember that we try to run a professional project in our spare time, on a budget of zero.
+- Be sure to check [the coding guidelines](https://github.com/javaparser/javaparser/wiki/Coding-Guidelines) which are easily used by installing the formatting rules as described there.
+- If you're new and like to casually contribute something, check out the [easy issues](https://github.com/javaparser/javaparser/labels/Easy).
+- If you're new and would like to become a member, start your own project that uses JavaParser.
+We noticed we get the best feedback from those. 
+Here are [some fun project ideas](https://github.com/javaparser/javaparser/labels/fun%20project%20idea).
+- If you start working on an issue, please say so with a comment in the issue.
+- If you know how to fix a problem, please fix it and open a pull request instead of opening an issue.
+
+Thanks for helping!
+
+## Contribution Workflow
+
+Our development workflow is based on Pull Request. If you are not familiar with the Pull Requests, we suggest you to checkout the [Github Documentation](https://help.github.com/articles/creating-a-pull-request/) for more information.
+
+1. **Fork** the JavaParser project. If you already have a fork, ensure to fetch the latest commits.
+2. In your forked project, **create a branch** related to the issue you are working on. This is important to ensure that your pull request will not contain unrelated work.
+3. When your work in your branch is done, **push your branch to your forked repository**.
+4. Go back to the [javaparser project site](https://github.com/javaparser/javaparser) and it should have a message offering to **create a pull request**. If it doesn't you can [create one manually](https://github.com/javaparser/javaparser/compare).
+
+### Remember:
+- A pull request should include tests. You can either use BDD ([more information here](https://github.com/javaparser/javaparser/wiki/Testing)) or JUnit.
+- Every pull request will automatically be checked by a few tools. Make sure AppVeyor and Travis are green.
+- Pull requests often stay open for at least a few days to give people a chance to review it.
+- A pull request is merged when all comments on it have been resolved.
+- If you create a pull request for an issue, mention the issue in the format #123 to make github link it automatically.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..012ddda
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,6 @@
+JavaParser is available either under the terms of the LGPL License or the Apache License. You as the user are entitled to choose the terms under which to adopt JavaParser.
+
+For details about the LGPL License please refer to LICENSE.LGPL. Please note
+that LGPL is just an extension to GPL, located in LICENSE.GPL.
+
+For details about the Apache License please refer to LICENSE.APACHE
diff --git a/LICENSE.APACHE b/LICENSE.APACHE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE.APACHE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/LICENSE.GPL b/LICENSE.GPL
new file mode 100644
index 0000000..fb1a1b0
--- /dev/null
+++ b/LICENSE.GPL
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE

+                       Version 3, 29 June 2007

+

+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>

+ Everyone is permitted to copy and distribute verbatim copies

+ of this license document, but changing it is not allowed.

+

+                            Preamble

+

+  The GNU General Public License is a free, copyleft license for

+software and other kinds of works.

+

+  The licenses for most software and other practical works are designed

+to take away your freedom to share and change the works.  By contrast,

+the GNU General Public License is intended to guarantee your freedom to

+share and change all versions of a program--to make sure it remains free

+software for all its users.  We, the Free Software Foundation, use the

+GNU General Public License for most of our software; it applies also to

+any other work released this way by its authors.  You can apply it to

+your programs, too.

+

+  When we speak of free software, we are referring to freedom, not

+price.  Our General Public Licenses are designed to make sure that you

+have the freedom to distribute copies of free software (and charge for

+them if you wish), that you receive source code or can get it if you

+want it, that you can change the software or use pieces of it in new

+free programs, and that you know you can do these things.

+

+  To protect your rights, we need to prevent others from denying you

+these rights or asking you to surrender the rights.  Therefore, you have

+certain responsibilities if you distribute copies of the software, or if

+you modify it: responsibilities to respect the freedom of others.

+

+  For example, if you distribute copies of such a program, whether

+gratis or for a fee, you must pass on to the recipients the same

+freedoms that you received.  You must make sure that they, too, receive

+or can get the source code.  And you must show them these terms so they

+know their rights.

+

+  Developers that use the GNU GPL protect your rights with two steps:

+(1) assert copyright on the software, and (2) offer you this License

+giving you legal permission to copy, distribute and/or modify it.

+

+  For the developers' and authors' protection, the GPL clearly explains

+that there is no warranty for this free software.  For both users' and

+authors' sake, the GPL requires that modified versions be marked as

+changed, so that their problems will not be attributed erroneously to

+authors of previous versions.

+

+  Some devices are designed to deny users access to install or run

+modified versions of the software inside them, although the manufacturer

+can do so.  This is fundamentally incompatible with the aim of

+protecting users' freedom to change the software.  The systematic

+pattern of such abuse occurs in the area of products for individuals to

+use, which is precisely where it is most unacceptable.  Therefore, we

+have designed this version of the GPL to prohibit the practice for those

+products.  If such problems arise substantially in other domains, we

+stand ready to extend this provision to those domains in future versions

+of the GPL, as needed to protect the freedom of users.

+

+  Finally, every program is threatened constantly by software patents.

+States should not allow patents to restrict development and use of

+software on general-purpose computers, but in those that do, we wish to

+avoid the special danger that patents applied to a free program could

+make it effectively proprietary.  To prevent this, the GPL assures that

+patents cannot be used to render the program non-free.

+

+  The precise terms and conditions for copying, distribution and

+modification follow.

+

+                       TERMS AND CONDITIONS

+

+  0. Definitions.

+

+  "This License" refers to version 3 of the GNU General Public License.

+

+  "Copyright" also means copyright-like laws that apply to other kinds of

+works, such as semiconductor masks.

+

+  "The Program" refers to any copyrightable work licensed under this

+License.  Each licensee is addressed as "you".  "Licensees" and

+"recipients" may be individuals or organizations.

+

+  To "modify" a work means to copy from or adapt all or part of the work

+in a fashion requiring copyright permission, other than the making of an

+exact copy.  The resulting work is called a "modified version" of the

+earlier work or a work "based on" the earlier work.

+

+  A "covered work" means either the unmodified Program or a work based

+on the Program.

+

+  To "propagate" a work means to do anything with it that, without

+permission, would make you directly or secondarily liable for

+infringement under applicable copyright law, except executing it on a

+computer or modifying a private copy.  Propagation includes copying,

+distribution (with or without modification), making available to the

+public, and in some countries other activities as well.

+

+  To "convey" a work means any kind of propagation that enables other

+parties to make or receive copies.  Mere interaction with a user through

+a computer network, with no transfer of a copy, is not conveying.

+

+  An interactive user interface displays "Appropriate Legal Notices"

+to the extent that it includes a convenient and prominently visible

+feature that (1) displays an appropriate copyright notice, and (2)

+tells the user that there is no warranty for the work (except to the

+extent that warranties are provided), that licensees may convey the

+work under this License, and how to view a copy of this License.  If

+the interface presents a list of user commands or options, such as a

+menu, a prominent item in the list meets this criterion.

+

+  1. Source Code.

+

+  The "source code" for a work means the preferred form of the work

+for making modifications to it.  "Object code" means any non-source

+form of a work.

+

+  A "Standard Interface" means an interface that either is an official

+standard defined by a recognized standards body, or, in the case of

+interfaces specified for a particular programming language, one that

+is widely used among developers working in that language.

+

+  The "System Libraries" of an executable work include anything, other

+than the work as a whole, that (a) is included in the normal form of

+packaging a Major Component, but which is not part of that Major

+Component, and (b) serves only to enable use of the work with that

+Major Component, or to implement a Standard Interface for which an

+implementation is available to the public in source code form.  A

+"Major Component", in this context, means a major essential component

+(kernel, window system, and so on) of the specific operating system

+(if any) on which the executable work runs, or a compiler used to

+produce the work, or an object code interpreter used to run it.

+

+  The "Corresponding Source" for a work in object code form means all

+the source code needed to generate, install, and (for an executable

+work) run the object code and to modify the work, including scripts to

+control those activities.  However, it does not include the work's

+System Libraries, or general-purpose tools or generally available free

+programs which are used unmodified in performing those activities but

+which are not part of the work.  For example, Corresponding Source

+includes interface definition files associated with source files for

+the work, and the source code for shared libraries and dynamically

+linked subprograms that the work is specifically designed to require,

+such as by intimate data communication or control flow between those

+subprograms and other parts of the work.

+

+  The Corresponding Source need not include anything that users

+can regenerate automatically from other parts of the Corresponding

+Source.

+

+  The Corresponding Source for a work in source code form is that

+same work.

+

+  2. Basic Permissions.

+

+  All rights granted under this License are granted for the term of

+copyright on the Program, and are irrevocable provided the stated

+conditions are met.  This License explicitly affirms your unlimited

+permission to run the unmodified Program.  The output from running a

+covered work is covered by this License only if the output, given its

+content, constitutes a covered work.  This License acknowledges your

+rights of fair use or other equivalent, as provided by copyright law.

+

+  You may make, run and propagate covered works that you do not

+convey, without conditions so long as your license otherwise remains

+in force.  You may convey covered works to others for the sole purpose

+of having them make modifications exclusively for you, or provide you

+with facilities for running those works, provided that you comply with

+the terms of this License in conveying all material for which you do

+not control copyright.  Those thus making or running the covered works

+for you must do so exclusively on your behalf, under your direction

+and control, on terms that prohibit them from making any copies of

+your copyrighted material outside their relationship with you.

+

+  Conveying under any other circumstances is permitted solely under

+the conditions stated below.  Sublicensing is not allowed; section 10

+makes it unnecessary.

+

+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

+

+  No covered work shall be deemed part of an effective technological

+measure under any applicable law fulfilling obligations under article

+11 of the WIPO copyright treaty adopted on 20 December 1996, or

+similar laws prohibiting or restricting circumvention of such

+measures.

+

+  When you convey a covered work, you waive any legal power to forbid

+circumvention of technological measures to the extent such circumvention

+is effected by exercising rights under this License with respect to

+the covered work, and you disclaim any intention to limit operation or

+modification of the work as a means of enforcing, against the work's

+users, your or third parties' legal rights to forbid circumvention of

+technological measures.

+

+  4. Conveying Verbatim Copies.

+

+  You may convey verbatim copies of the Program's source code as you

+receive it, in any medium, provided that you conspicuously and

+appropriately publish on each copy an appropriate copyright notice;

+keep intact all notices stating that this License and any

+non-permissive terms added in accord with section 7 apply to the code;

+keep intact all notices of the absence of any warranty; and give all

+recipients a copy of this License along with the Program.

+

+  You may charge any price or no price for each copy that you convey,

+and you may offer support or warranty protection for a fee.

+

+  5. Conveying Modified Source Versions.

+

+  You may convey a work based on the Program, or the modifications to

+produce it from the Program, in the form of source code under the

+terms of section 4, provided that you also meet all of these conditions:

+

+    a) The work must carry prominent notices stating that you modified

+    it, and giving a relevant date.

+

+    b) The work must carry prominent notices stating that it is

+    released under this License and any conditions added under section

+    7.  This requirement modifies the requirement in section 4 to

+    "keep intact all notices".

+

+    c) You must license the entire work, as a whole, under this

+    License to anyone who comes into possession of a copy.  This

+    License will therefore apply, along with any applicable section 7

+    additional terms, to the whole of the work, and all its parts,

+    regardless of how they are packaged.  This License gives no

+    permission to license the work in any other way, but it does not

+    invalidate such permission if you have separately received it.

+

+    d) If the work has interactive user interfaces, each must display

+    Appropriate Legal Notices; however, if the Program has interactive

+    interfaces that do not display Appropriate Legal Notices, your

+    work need not make them do so.

+

+  A compilation of a covered work with other separate and independent

+works, which are not by their nature extensions of the covered work,

+and which are not combined with it such as to form a larger program,

+in or on a volume of a storage or distribution medium, is called an

+"aggregate" if the compilation and its resulting copyright are not

+used to limit the access or legal rights of the compilation's users

+beyond what the individual works permit.  Inclusion of a covered work

+in an aggregate does not cause this License to apply to the other

+parts of the aggregate.

+

+  6. Conveying Non-Source Forms.

+

+  You may convey a covered work in object code form under the terms

+of sections 4 and 5, provided that you also convey the

+machine-readable Corresponding Source under the terms of this License,

+in one of these ways:

+

+    a) Convey the object code in, or embodied in, a physical product

+    (including a physical distribution medium), accompanied by the

+    Corresponding Source fixed on a durable physical medium

+    customarily used for software interchange.

+

+    b) Convey the object code in, or embodied in, a physical product

+    (including a physical distribution medium), accompanied by a

+    written offer, valid for at least three years and valid for as

+    long as you offer spare parts or customer support for that product

+    model, to give anyone who possesses the object code either (1) a

+    copy of the Corresponding Source for all the software in the

+    product that is covered by this License, on a durable physical

+    medium customarily used for software interchange, for a price no

+    more than your reasonable cost of physically performing this

+    conveying of source, or (2) access to copy the

+    Corresponding Source from a network server at no charge.

+

+    c) Convey individual copies of the object code with a copy of the

+    written offer to provide the Corresponding Source.  This

+    alternative is allowed only occasionally and noncommercially, and

+    only if you received the object code with such an offer, in accord

+    with subsection 6b.

+

+    d) Convey the object code by offering access from a designated

+    place (gratis or for a charge), and offer equivalent access to the

+    Corresponding Source in the same way through the same place at no

+    further charge.  You need not require recipients to copy the

+    Corresponding Source along with the object code.  If the place to

+    copy the object code is a network server, the Corresponding Source

+    may be on a different server (operated by you or a third party)

+    that supports equivalent copying facilities, provided you maintain

+    clear directions next to the object code saying where to find the

+    Corresponding Source.  Regardless of what server hosts the

+    Corresponding Source, you remain obligated to ensure that it is

+    available for as long as needed to satisfy these requirements.

+

+    e) Convey the object code using peer-to-peer transmission, provided

+    you inform other peers where the object code and Corresponding

+    Source of the work are being offered to the general public at no

+    charge under subsection 6d.

+

+  A separable portion of the object code, whose source code is excluded

+from the Corresponding Source as a System Library, need not be

+included in conveying the object code work.

+

+  A "User Product" is either (1) a "consumer product", which means any

+tangible personal property which is normally used for personal, family,

+or household purposes, or (2) anything designed or sold for incorporation

+into a dwelling.  In determining whether a product is a consumer product,

+doubtful cases shall be resolved in favor of coverage.  For a particular

+product received by a particular user, "normally used" refers to a

+typical or common use of that class of product, regardless of the status

+of the particular user or of the way in which the particular user

+actually uses, or expects or is expected to use, the product.  A product

+is a consumer product regardless of whether the product has substantial

+commercial, industrial or non-consumer uses, unless such uses represent

+the only significant mode of use of the product.

+

+  "Installation Information" for a User Product means any methods,

+procedures, authorization keys, or other information required to install

+and execute modified versions of a covered work in that User Product from

+a modified version of its Corresponding Source.  The information must

+suffice to ensure that the continued functioning of the modified object

+code is in no case prevented or interfered with solely because

+modification has been made.

+

+  If you convey an object code work under this section in, or with, or

+specifically for use in, a User Product, and the conveying occurs as

+part of a transaction in which the right of possession and use of the

+User Product is transferred to the recipient in perpetuity or for a

+fixed term (regardless of how the transaction is characterized), the

+Corresponding Source conveyed under this section must be accompanied

+by the Installation Information.  But this requirement does not apply

+if neither you nor any third party retains the ability to install

+modified object code on the User Product (for example, the work has

+been installed in ROM).

+

+  The requirement to provide Installation Information does not include a

+requirement to continue to provide support service, warranty, or updates

+for a work that has been modified or installed by the recipient, or for

+the User Product in which it has been modified or installed.  Access to a

+network may be denied when the modification itself materially and

+adversely affects the operation of the network or violates the rules and

+protocols for communication across the network.

+

+  Corresponding Source conveyed, and Installation Information provided,

+in accord with this section must be in a format that is publicly

+documented (and with an implementation available to the public in

+source code form), and must require no special password or key for

+unpacking, reading or copying.

+

+  7. Additional Terms.

+

+  "Additional permissions" are terms that supplement the terms of this

+License by making exceptions from one or more of its conditions.

+Additional permissions that are applicable to the entire Program shall

+be treated as though they were included in this License, to the extent

+that they are valid under applicable law.  If additional permissions

+apply only to part of the Program, that part may be used separately

+under those permissions, but the entire Program remains governed by

+this License without regard to the additional permissions.

+

+  When you convey a copy of a covered work, you may at your option

+remove any additional permissions from that copy, or from any part of

+it.  (Additional permissions may be written to require their own

+removal in certain cases when you modify the work.)  You may place

+additional permissions on material, added by you to a covered work,

+for which you have or can give appropriate copyright permission.

+

+  Notwithstanding any other provision of this License, for material you

+add to a covered work, you may (if authorized by the copyright holders of

+that material) supplement the terms of this License with terms:

+

+    a) Disclaiming warranty or limiting liability differently from the

+    terms of sections 15 and 16 of this License; or

+

+    b) Requiring preservation of specified reasonable legal notices or

+    author attributions in that material or in the Appropriate Legal

+    Notices displayed by works containing it; or

+

+    c) Prohibiting misrepresentation of the origin of that material, or

+    requiring that modified versions of such material be marked in

+    reasonable ways as different from the original version; or

+

+    d) Limiting the use for publicity purposes of names of licensors or

+    authors of the material; or

+

+    e) Declining to grant rights under trademark law for use of some

+    trade names, trademarks, or service marks; or

+

+    f) Requiring indemnification of licensors and authors of that

+    material by anyone who conveys the material (or modified versions of

+    it) with contractual assumptions of liability to the recipient, for

+    any liability that these contractual assumptions directly impose on

+    those licensors and authors.

+

+  All other non-permissive additional terms are considered "further

+restrictions" within the meaning of section 10.  If the Program as you

+received it, or any part of it, contains a notice stating that it is

+governed by this License along with a term that is a further

+restriction, you may remove that term.  If a license document contains

+a further restriction but permits relicensing or conveying under this

+License, you may add to a covered work material governed by the terms

+of that license document, provided that the further restriction does

+not survive such relicensing or conveying.

+

+  If you add terms to a covered work in accord with this section, you

+must place, in the relevant source files, a statement of the

+additional terms that apply to those files, or a notice indicating

+where to find the applicable terms.

+

+  Additional terms, permissive or non-permissive, may be stated in the

+form of a separately written license, or stated as exceptions;

+the above requirements apply either way.

+

+  8. Termination.

+

+  You may not propagate or modify a covered work except as expressly

+provided under this License.  Any attempt otherwise to propagate or

+modify it is void, and will automatically terminate your rights under

+this License (including any patent licenses granted under the third

+paragraph of section 11).

+

+  However, if you cease all violation of this License, then your

+license from a particular copyright holder is reinstated (a)

+provisionally, unless and until the copyright holder explicitly and

+finally terminates your license, and (b) permanently, if the copyright

+holder fails to notify you of the violation by some reasonable means

+prior to 60 days after the cessation.

+

+  Moreover, your license from a particular copyright holder is

+reinstated permanently if the copyright holder notifies you of the

+violation by some reasonable means, this is the first time you have

+received notice of violation of this License (for any work) from that

+copyright holder, and you cure the violation prior to 30 days after

+your receipt of the notice.

+

+  Termination of your rights under this section does not terminate the

+licenses of parties who have received copies or rights from you under

+this License.  If your rights have been terminated and not permanently

+reinstated, you do not qualify to receive new licenses for the same

+material under section 10.

+

+  9. Acceptance Not Required for Having Copies.

+

+  You are not required to accept this License in order to receive or

+run a copy of the Program.  Ancillary propagation of a covered work

+occurring solely as a consequence of using peer-to-peer transmission

+to receive a copy likewise does not require acceptance.  However,

+nothing other than this License grants you permission to propagate or

+modify any covered work.  These actions infringe copyright if you do

+not accept this License.  Therefore, by modifying or propagating a

+covered work, you indicate your acceptance of this License to do so.

+

+  10. Automatic Licensing of Downstream Recipients.

+

+  Each time you convey a covered work, the recipient automatically

+receives a license from the original licensors, to run, modify and

+propagate that work, subject to this License.  You are not responsible

+for enforcing compliance by third parties with this License.

+

+  An "entity transaction" is a transaction transferring control of an

+organization, or substantially all assets of one, or subdividing an

+organization, or merging organizations.  If propagation of a covered

+work results from an entity transaction, each party to that

+transaction who receives a copy of the work also receives whatever

+licenses to the work the party's predecessor in interest had or could

+give under the previous paragraph, plus a right to possession of the

+Corresponding Source of the work from the predecessor in interest, if

+the predecessor has it or can get it with reasonable efforts.

+

+  You may not impose any further restrictions on the exercise of the

+rights granted or affirmed under this License.  For example, you may

+not impose a license fee, royalty, or other charge for exercise of

+rights granted under this License, and you may not initiate litigation

+(including a cross-claim or counterclaim in a lawsuit) alleging that

+any patent claim is infringed by making, using, selling, offering for

+sale, or importing the Program or any portion of it.

+

+  11. Patents.

+

+  A "contributor" is a copyright holder who authorizes use under this

+License of the Program or a work on which the Program is based.  The

+work thus licensed is called the contributor's "contributor version".

+

+  A contributor's "essential patent claims" are all patent claims

+owned or controlled by the contributor, whether already acquired or

+hereafter acquired, that would be infringed by some manner, permitted

+by this License, of making, using, or selling its contributor version,

+but do not include claims that would be infringed only as a

+consequence of further modification of the contributor version.  For

+purposes of this definition, "control" includes the right to grant

+patent sublicenses in a manner consistent with the requirements of

+this License.

+

+  Each contributor grants you a non-exclusive, worldwide, royalty-free

+patent license under the contributor's essential patent claims, to

+make, use, sell, offer for sale, import and otherwise run, modify and

+propagate the contents of its contributor version.

+

+  In the following three paragraphs, a "patent license" is any express

+agreement or commitment, however denominated, not to enforce a patent

+(such as an express permission to practice a patent or covenant not to

+sue for patent infringement).  To "grant" such a patent license to a

+party means to make such an agreement or commitment not to enforce a

+patent against the party.

+

+  If you convey a covered work, knowingly relying on a patent license,

+and the Corresponding Source of the work is not available for anyone

+to copy, free of charge and under the terms of this License, through a

+publicly available network server or other readily accessible means,

+then you must either (1) cause the Corresponding Source to be so

+available, or (2) arrange to deprive yourself of the benefit of the

+patent license for this particular work, or (3) arrange, in a manner

+consistent with the requirements of this License, to extend the patent

+license to downstream recipients.  "Knowingly relying" means you have

+actual knowledge that, but for the patent license, your conveying the

+covered work in a country, or your recipient's use of the covered work

+in a country, would infringe one or more identifiable patents in that

+country that you have reason to believe are valid.

+

+  If, pursuant to or in connection with a single transaction or

+arrangement, you convey, or propagate by procuring conveyance of, a

+covered work, and grant a patent license to some of the parties

+receiving the covered work authorizing them to use, propagate, modify

+or convey a specific copy of the covered work, then the patent license

+you grant is automatically extended to all recipients of the covered

+work and works based on it.

+

+  A patent license is "discriminatory" if it does not include within

+the scope of its coverage, prohibits the exercise of, or is

+conditioned on the non-exercise of one or more of the rights that are

+specifically granted under this License.  You may not convey a covered

+work if you are a party to an arrangement with a third party that is

+in the business of distributing software, under which you make payment

+to the third party based on the extent of your activity of conveying

+the work, and under which the third party grants, to any of the

+parties who would receive the covered work from you, a discriminatory

+patent license (a) in connection with copies of the covered work

+conveyed by you (or copies made from those copies), or (b) primarily

+for and in connection with specific products or compilations that

+contain the covered work, unless you entered into that arrangement,

+or that patent license was granted, prior to 28 March 2007.

+

+  Nothing in this License shall be construed as excluding or limiting

+any implied license or other defenses to infringement that may

+otherwise be available to you under applicable patent law.

+

+  12. No Surrender of Others' Freedom.

+

+  If conditions are imposed on you (whether by court order, agreement or

+otherwise) that contradict the conditions of this License, they do not

+excuse you from the conditions of this License.  If you cannot convey a

+covered work so as to satisfy simultaneously your obligations under this

+License and any other pertinent obligations, then as a consequence you may

+not convey it at all.  For example, if you agree to terms that obligate you

+to collect a royalty for further conveying from those to whom you convey

+the Program, the only way you could satisfy both those terms and this

+License would be to refrain entirely from conveying the Program.

+

+  13. Use with the GNU Affero General Public License.

+

+  Notwithstanding any other provision of this License, you have

+permission to link or combine any covered work with a work licensed

+under version 3 of the GNU Affero General Public License into a single

+combined work, and to convey the resulting work.  The terms of this

+License will continue to apply to the part which is the covered work,

+but the special requirements of the GNU Affero General Public License,

+section 13, concerning interaction through a network will apply to the

+combination as such.

+

+  14. Revised Versions of this License.

+

+  The Free Software Foundation may publish revised and/or new versions of

+the GNU General Public License from time to time.  Such new versions will

+be similar in spirit to the present version, but may differ in detail to

+address new problems or concerns.

+

+  Each version is given a distinguishing version number.  If the

+Program specifies that a certain numbered version of the GNU General

+Public License "or any later version" applies to it, you have the

+option of following the terms and conditions either of that numbered

+version or of any later version published by the Free Software

+Foundation.  If the Program does not specify a version number of the

+GNU General Public License, you may choose any version ever published

+by the Free Software Foundation.

+

+  If the Program specifies that a proxy can decide which future

+versions of the GNU General Public License can be used, that proxy's

+public statement of acceptance of a version permanently authorizes you

+to choose that version for the Program.

+

+  Later license versions may give you additional or different

+permissions.  However, no additional obligations are imposed on any

+author or copyright holder as a result of your choosing to follow a

+later version.

+

+  15. Disclaimer of Warranty.

+

+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY

+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT

+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY

+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,

+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR

+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM

+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF

+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

+

+  16. Limitation of Liability.

+

+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING

+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS

+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY

+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE

+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF

+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD

+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),

+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF

+SUCH DAMAGES.

+

+  17. Interpretation of Sections 15 and 16.

+

+  If the disclaimer of warranty and limitation of liability provided

+above cannot be given local legal effect according to their terms,

+reviewing courts shall apply local law that most closely approximates

+an absolute waiver of all civil liability in connection with the

+Program, unless a warranty or assumption of liability accompanies a

+copy of the Program in return for a fee.

+

+                     END OF TERMS AND CONDITIONS

+

+            How to Apply These Terms to Your New Programs

+

+  If you develop a new program, and you want it to be of the greatest

+possible use to the public, the best way to achieve this is to make it

+free software which everyone can redistribute and change under these terms.

+

+  To do so, attach the following notices to the program.  It is safest

+to attach them to the start of each source file to most effectively

+state the exclusion of warranty; and each file should have at least

+the "copyright" line and a pointer to where the full notice is found.

+

+    Java 1.5 japa.parser and Abstract Syntax Tree

+    Copyright (C) 2007  J�lio Vilmar Gesser

+

+    This program is free software: you can redistribute it and/or modify

+    it under the terms of the GNU General Public License as published by

+    the Free Software Foundation, either version 3 of the License, or

+    (at your option) any later version.

+

+    This program is distributed in the hope that it will be useful,

+    but WITHOUT ANY WARRANTY; without even the implied warranty of

+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+    GNU General Public License for more details.

+

+    You should have received a copy of the GNU General Public License

+    along with this program.  If not, see <http://www.gnu.org/licenses/>.

+

+Also add information on how to contact you by electronic and paper mail.

+

+  If the program does terminal interaction, make it output a short

+notice like this when it starts in an interactive mode:

+

+    Java 1.5 japa.parser and Abstract Syntax Tree  Copyright (C) 2007  J�lio Vilmar Gesser

+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.

+    This is free software, and you are welcome to redistribute it

+    under certain conditions; type `show c' for details.

+

+The hypothetical commands `show w' and `show c' should show the appropriate

+parts of the General Public License.  Of course, your program's commands

+might be different; for a GUI interface, you would use an "about box".

+

+  You should also get your employer (if you work as a programmer) or school,

+if any, to sign a "copyright disclaimer" for the program, if necessary.

+For more information on this, and how to apply and follow the GNU GPL, see

+<http://www.gnu.org/licenses/>.

+

+  The GNU General Public License does not permit incorporating your program

+into proprietary programs.  If your program is a subroutine library, you

+may consider it more useful to permit linking proprietary applications with

+the library.  If this is what you want to do, use the GNU Lesser General

+Public License instead of this License.  But first, please read

+<http://www.gnu.org/philosophy/why-not-lgpl.html>.

diff --git a/LICENSE.LGPL b/LICENSE.LGPL
new file mode 100644
index 0000000..b87303c
--- /dev/null
+++ b/LICENSE.LGPL
@@ -0,0 +1,165 @@
+		   GNU LESSER GENERAL PUBLIC LICENSE

+                       Version 3, 29 June 2007

+

+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>

+ Everyone is permitted to copy and distribute verbatim copies

+ of this license document, but changing it is not allowed.

+

+

+  This version of the GNU Lesser General Public License incorporates

+the terms and conditions of version 3 of the GNU General Public

+License, supplemented by the additional permissions listed below.

+

+  0. Additional Definitions. 

+

+  As used herein, "this License" refers to version 3 of the GNU Lesser

+General Public License, and the "GNU GPL" refers to version 3 of the GNU

+General Public License.

+

+  "The Library" refers to a covered work governed by this License,

+other than an Application or a Combined Work as defined below.

+

+  An "Application" is any work that makes use of an interface provided

+by the Library, but which is not otherwise based on the Library.

+Defining a subclass of a class defined by the Library is deemed a mode

+of using an interface provided by the Library.

+

+  A "Combined Work" is a work produced by combining or linking an

+Application with the Library.  The particular version of the Library

+with which the Combined Work was made is also called the "Linked

+Version".

+

+  The "Minimal Corresponding Source" for a Combined Work means the

+Corresponding Source for the Combined Work, excluding any source code

+for portions of the Combined Work that, considered in isolation, are

+based on the Application, and not on the Linked Version.

+

+  The "Corresponding Application Code" for a Combined Work means the

+object code and/or source code for the Application, including any data

+and utility programs needed for reproducing the Combined Work from the

+Application, but excluding the System Libraries of the Combined Work.

+

+  1. Exception to Section 3 of the GNU GPL.

+

+  You may convey a covered work under sections 3 and 4 of this License

+without being bound by section 3 of the GNU GPL.

+

+  2. Conveying Modified Versions.

+

+  If you modify a copy of the Library, and, in your modifications, a

+facility refers to a function or data to be supplied by an Application

+that uses the facility (other than as an argument passed when the

+facility is invoked), then you may convey a copy of the modified

+version:

+

+   a) under this License, provided that you make a good faith effort to

+   ensure that, in the event an Application does not supply the

+   function or data, the facility still operates, and performs

+   whatever part of its purpose remains meaningful, or

+

+   b) under the GNU GPL, with none of the additional permissions of

+   this License applicable to that copy.

+

+  3. Object Code Incorporating Material from Library Header Files.

+

+  The object code form of an Application may incorporate material from

+a header file that is part of the Library.  You may convey such object

+code under terms of your choice, provided that, if the incorporated

+material is not limited to numerical parameters, data structure

+layouts and accessors, or small macros, inline functions and templates

+(ten or fewer lines in length), you do both of the following:

+

+   a) Give prominent notice with each copy of the object code that the

+   Library is used in it and that the Library and its use are

+   covered by this License.

+

+   b) Accompany the object code with a copy of the GNU GPL and this license

+   document.

+

+  4. Combined Works.

+

+  You may convey a Combined Work under terms of your choice that,

+taken together, effectively do not restrict modification of the

+portions of the Library contained in the Combined Work and reverse

+engineering for debugging such modifications, if you also do each of

+the following:

+

+   a) Give prominent notice with each copy of the Combined Work that

+   the Library is used in it and that the Library and its use are

+   covered by this License.

+

+   b) Accompany the Combined Work with a copy of the GNU GPL and this license

+   document.

+

+   c) For a Combined Work that displays copyright notices during

+   execution, include the copyright notice for the Library among

+   these notices, as well as a reference directing the user to the

+   copies of the GNU GPL and this license document.

+

+   d) Do one of the following:

+

+       0) Convey the Minimal Corresponding Source under the terms of this

+       License, and the Corresponding Application Code in a form

+       suitable for, and under terms that permit, the user to

+       recombine or relink the Application with a modified version of

+       the Linked Version to produce a modified Combined Work, in the

+       manner specified by section 6 of the GNU GPL for conveying

+       Corresponding Source.

+

+       1) Use a suitable shared library mechanism for linking with the

+       Library.  A suitable mechanism is one that (a) uses at run time

+       a copy of the Library already present on the user's computer

+       system, and (b) will operate properly with a modified version

+       of the Library that is interface-compatible with the Linked

+       Version. 

+

+   e) Provide Installation Information, but only if you would otherwise

+   be required to provide such information under section 6 of the

+   GNU GPL, and only to the extent that such information is

+   necessary to install and execute a modified version of the

+   Combined Work produced by recombining or relinking the

+   Application with a modified version of the Linked Version. (If

+   you use option 4d0, the Installation Information must accompany

+   the Minimal Corresponding Source and Corresponding Application

+   Code. If you use option 4d1, you must provide the Installation

+   Information in the manner specified by section 6 of the GNU GPL

+   for conveying Corresponding Source.)

+

+  5. Combined Libraries.

+

+  You may place library facilities that are a work based on the

+Library side by side in a single library together with other library

+facilities that are not Applications and are not covered by this

+License, and convey such a combined library under terms of your

+choice, if you do both of the following:

+

+   a) Accompany the combined library with a copy of the same work based

+   on the Library, uncombined with any other library facilities,

+   conveyed under the terms of this License.

+

+   b) Give prominent notice with the combined library that part of it

+   is a work based on the Library, and explaining where to find the

+   accompanying uncombined form of the same work.

+

+  6. Revised Versions of the GNU Lesser General Public License.

+

+  The Free Software Foundation may publish revised and/or new versions

+of the GNU Lesser General Public License from time to time. Such new

+versions will be similar in spirit to the present version, but may

+differ in detail to address new problems or concerns.

+

+  Each version is given a distinguishing version number. If the

+Library as you received it specifies that a certain numbered version

+of the GNU Lesser General Public License "or any later version"

+applies to it, you have the option of following the terms and

+conditions either of that published version or of any later version

+published by the Free Software Foundation. If the Library as you

+received it does not specify a version number of the GNU Lesser

+General Public License, you may choose any version of the GNU Lesser

+General Public License ever published by the Free Software Foundation.

+

+  If the Library as you received it specifies that a proxy can decide

+whether future versions of the GNU Lesser General Public License shall

+apply, that proxy's public statement of acceptance of any version is

+permanent authorization for you to choose that version for the

+Library.

diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..f881bfc
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,23 @@
+version: '{build}'
+os: Windows Server 2012
+install:
+  - ps: |
+      Add-Type -AssemblyName System.IO.Compression.FileSystem
+      if (!(Test-Path -Path "C:\maven" )) {
+        (new-object System.Net.WebClient).DownloadFile(
+          'http://www.us.apache.org/dist/maven/maven-3/3.2.5/binaries/apache-maven-3.2.5-bin.zip',
+          'C:\maven-bin.zip'
+        )
+        [System.IO.Compression.ZipFile]::ExtractToDirectory("C:\maven-bin.zip", "C:\maven")
+      }
+  - cmd: SET PATH=C:\maven\apache-maven-3.2.5\bin;%JAVA_HOME%\bin;%PATH%
+  - cmd: SET MAVEN_OPTS=-XX:MaxPermSize=2g -Xmx4g
+  - cmd: SET JAVA_OPTS=-XX:MaxPermSize=2g -Xmx4g
+  - cmd: SET M2_HOME=C:\maven\apache-maven-3.2.5
+build_script:
+  - mvn clean package --batch-mode -DskipTest
+test_script:
+  - mvn clean install --batch-mode
+cache:
+  - C:\maven\
+  - C:\Users\appveyor\.m2
\ No newline at end of file
diff --git a/changelog.md b/changelog.md
new file mode 100644
index 0000000..192f146
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,677 @@
+Version 3.5.15
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/78?closed=1)
+* Java 10 support is complete.
+* BREAKING: Java language level support has changed to make Java 10 support possible.
+[Here's a little article about it](https://matozoid.github.io/2017/04/11/enable-java-9-support.html)
+
+Version 3.5.14
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/77?closed=1)
+* Java 10's `var` can now be parsed and will be turned into a `VarType` node.
+It can not be resolved yet.
+* `NodeList` now has a pretty complete set of `...First` and `...Last` methods.
+Thanks stephenramthun !
+
+Version 3.5.13
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/76?closed=1)
+* The Javadoc parser has received a lot of attention.
+
+Version 3.5.12
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/75?closed=1)
+* Thanks to un0btanium for fixing the readme file!
+
+Version 3.5.11
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/74?closed=1)
+* BREAKING: `AssignExpr.Operator.AND` is now `AssignExpr.Operator.BINARY_AND`.
+* BREAKING: `AssignExpr.Operator.OR` is now `AssignExpr.Operator.BINARY_OR`.
+* `getPrimaryTypeName` and `getPrimaryType` give access to the type that has the same name as the file it came from.
+* Enums will now get their constants aligned vertically if there are more than five.
+* You can now convert between `AssignExpr.Operator` and `AssignExpr.Operator` if you like.
+
+Version 3.5.10
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/73?closed=1)
+* JavaSymbolSolver is now in the same project as JavaParser, meaning they get released together from now on.
+* LexicalPreservingPrinter has had a big speed optimization.
+
+Version 3.5.9
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/72?closed=1)
+* BREAKING: the very confusing constructor `NodeList(Node)` (which sets the parent) was removed.
+* To avoid using the int type for token kinds, use the new `JavaToken.Kind` enum.
+It can convert to and from the int kind. 
+
+Version 3.5.8
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/71?closed=1)
+* the module name is now set to com.github.javaparser.core
+
+Version 3.5.7
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/70?closed=1)
+
+Version 3.5.6
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/69?closed=1)
+* `toSomeType()` methods have been added for many types that give more functional access to a subtype.
+* BETA: the below work on Java Symbol Solver is still ongoing.
+
+Version 3.5.5
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/68?closed=1)
+* SourceRoot is now silent by default - look at the Log class if you want to change that. 
+* BETA: the below work on Java Symbol Solver is still ongoing.
+
+Version 3.5.4
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/67?closed=1)
+* BETA: the below work on Java Symbol Solver is still ongoing.
+
+Version 3.5.3
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/66?closed=1)
+* Unicode escapes (`\u1234`) are now retained in the AST,
+    but they are now only allowed in comments, string and character literals, and identifiers. 
+* BETA: the below work on Java Symbol Solver is still ongoing.
+
+Version 3.5.2
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/65?closed=1)
+* The pretty printer now cleans up Javadoc comments.
+* BETA: the below work on Java Symbol Solver is still ongoing.
+
+Version 3.5.1
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/64?closed=1)
+* BETA: the below work on Java Symbol Solver is still ongoing.
+
+Version 3.5.0
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/63?closed=1)
+* A functional visitor API has been added. See [PR 1195](https://github.com/javaparser/javaparser/pull/1195) for now.
+* Build is working again on Windows thanks to Leonardo Herrera.
+* The pretty printer now has an option to order imports, also thanks to Leonardo Herrera.
+* Receiver parameters are now well-supported instead of being a hack. See [issue 1194](https://github.com/javaparser/javaparser/pull/1194) for a description.
+* BETA: the below work on Java Symbol Solver is still ongoing.
+
+Version 3.4.4
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/62?closed=1)
+* BETA: the below work on Java Symbol Solver is still ongoing.
+
+Version 3.4.3
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/61?closed=1)
+* BETA: we're still doing work to integrate parts of [Java Symbol Solver](https://github.com/javaparser/javasymbolsolver) to simplify its API.
+* `VisitorMap` is joined by `VisitorSet` and `VisitorList`, 
+for when you want to store `Node`s in collection but don't want its default equals/hascode behaviour
+
+Version 3.4.2
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/60?closed=1)
+* BETA: we're doing work to integrate parts of [Java Symbol Solver](https://github.com/javaparser/javasymbolsolver) to simplify its API.
+* JDK 9 will compile JavaParser now.
+* [An official sample Maven setup](https://github.com/javaparser/javaparser-maven-sample) was added.
+
+Version 3.4.1
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/59?closed=1)
+* Two visitors were added: `NoCommentEqualsVisitor` and `NoCommentHashCodeVisitor` - 
+as the name implies you can use these to compare nodes without considering comments.
+Thanks Ryan Beckett!
+* `isSomeType()` methods have been added for many types that help avoid `instanceof`.
+* `asSomeType()` methods have been added for many types that help avoid casting to that type.
+* `ifSomeType()` methods have been added for many types, giving a nice functional way of doing if-is-type-then-cast-to-type-then-use.
+* The `LexicalPreservingPrinter` had its API changed a little: setup and printing are now separate things,
+so you don't have to drag an instance of `LexicalPreservingPrinter` through your code anymore.  
+* `traverseScope` was added to all nodes with a scope, so you can travel through the scope without tripping over (non-)optionality.
+
+
+Version 3.4.0
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/58?closed=1)
+* BREAKING: We missed a Java 9 feature which is now on board: try with resources can now refer to a resource declared outside of the statement.
+This means that the node type you get for those resources is now `Expression` instead of `VariableDeclarationExpr`.
+For Java 8 and below you can simply cast it to `VariableDeclarationExpr` again.
+See also the Javadoc for `TryStmt`.
+* You can now inspect the AST by exporting it to XML, JSON, YAML, or a Graphviz's dot diagram, thanks to Ryan Beckett!
+* `GenericVisitorWithDefaults` and `VoidVisitorWithDefaults` were added which function like empty visitors, 
+but all the visit methods call a default method by default.
+* Annotation support was cleaned up, adding some obscure locations where you can have annotations.
+* `EnumDeclaration` regained its constructor builder methods. They were accidentally lost around 3.2.2.
+* `ArrayType` now has an `origin` field which indicates in which position the array brackets were found.
+
+Version 3.3.5
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/57?closed=1)
+
+Version 3.3.4
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/56?closed=1)
+* `SourceZip` has been added.
+Use it to read source code from jars or zip files.
+Thank you @ryan-beckett !
+* JavaCC was upgraded to 7.0.2
+* A new option for the pretty printer was added.
+You can now wrap-and-column-align parameters of method calls.
+Thank you @tarilabs !
+
+Version 3.3.3
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/55?closed=1)
+* Parsing a partial java file (like an expression or statement) no longer ignores trailing code.
+* New memory saving option: turn off token list.
+
+Version 3.3.2
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/54?closed=1)
+* `VisitorMap` lets you override hashcode/equals for nodes when used as a key for a map.
+
+Version 3.3.1
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/53?closed=1)
+* The token list is now mutable - see methods on `JavaToken`.
+This caused mild breakage - some fields have become `Optional`.
+
+Version 3.3.0
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/52?closed=1)
+* Breaking: `TryStmt::tryBlock` and `EnclosedExpr::inner` were optional for no good reason. Now they are required.
+* You can now ask a `JavaToken` for its category, which is useful for examining the token list or doing syntax highlighting or so.
+* `enum` and `strictfp` can now be used as identifiers on lower Java versions.
+
+Version 3.2.12
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/51?closed=1)
+
+Version 3.2.11
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/50?closed=1)
+* We're up to date with the latest Java 9 module system again.
+
+Version 3.2.10
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/49?closed=1)
+* `Node.replace(old, new)` was added, including property-specific `X.replaceY(newY)` methods
+
+Version 3.2.9
+------------------
+Scrapped due to release problem.
+
+Version 3.2.8
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/48?closed=1)
+* Added `isInnerClass()` that checks if a `ClassOrInterfaceDeclaration` is an inner class (note: this is different from a nested class!)
+* @ryan-beckett contributed a huge [Eclipse setup guide](https://github.com/javaparser/javaparser/wiki/Eclipse-Project-Setup-Guide)
+
+Version 3.2.7
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/47?closed=1)
+* We now recover from some parse errors! [Here is an article](https://matozoid.github.io/2017/06/11/parse-error-recovery.html)
+
+Version 3.2.6
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/46?closed=1)
+* `EmptyMemberDeclaration` is gone! 
+It was deprecated for a while because it it was in the AST, but doesn't have any meaning in a Java program. 
+`EmptyStmt` was also deprecated, but that has been reverted. 
+This node *does* have meaning.
+
+Version 3.2.5
+------------------
+[issues resolved](https://github.com/javaparser/javaparser/milestone/45?closed=1)
+* `NodeWithCondition` was added on all nodes containing a condition.
+* Lots of work on improving lexical preservation.
+* If a file was parsed from a file system, you can now get path information etc. from `CompilationUnit`
+* API BREAKING: every node now points to its start and end token.
+Some of the API has started returning `TokenRange` instead of `Range` - you can call `toRange` to get the old object type.
+We may still change the naming of some of this code in the following month.
+
+Version 3.2.4
+------------------
+New style changelog, no more issue numbers, but a link: 
+[issues resolved](https://github.com/javaparser/javaparser/milestone/44?closed=1)
+and any notable changes:
+* the new method `Node.removeForced()` by removing it, or removing the first parent that is optional.
+This is different from `Node.remove()`, `remove()` only tries to remove the node from the parent and fails if it can't.
+* `FieldAccessExpr.scope` is now a required property.
+You might find some `get()`s in your code that are no longer necessary.
+* `ReferenceType` no longer has a type parameter, so every `ReferenceType<?>` can be replaced by `ReferenceType` now.
+
+Version 3.2.3
+------------------
+* 907 906 905 903 911 910 909 908 smaller improvements and fixes
+
+Version 3.2.2
+------------------
+Beta: `TreeStructureVisitor`.
+
+* 770 902 904 901 smaller improvements and fixes
+
+Version 3.2.1
+------------------
+Beta: `TreeStructureVisitor`.
+
+* Maven dependencies were updated to their latest versions 
+* 890 the concept of "method signature" now exists in JavaParser
+* 896 891 889 887 882 789 smaller improvements and fixes
+
+Version 3.2.0
+------------------
+The lexical preservation code is stable!
+
+Beta: `TreeStructureVisitor`.
+
+* 885 884 879 878 smaller improvements and fixes
+
+Version 3.1.4
+------------------
+This is the first version to parse Java 9.
+
+Beta: `TreeStructureVisitor`, and `LexicalPreservingPrinter`.
+
+* 872 873 874 787 Remaining Java 9 work.
+
+Version 3.1.3
+------------------
+Beta: `TreeStructureVisitor`, and `LexicalPreservingPrinter`.
+
+A start has been made on source level support. The default level is Java 8.
+It can be set to Java 9 like this for a parser *instance*:
+```java
+private final JavaParser parser = new JavaParser(new ParserConfiguration().setValidator(new Java9Validator()));
+```
+and like this for the static parse methods:
+```java
+JavaParser.getStaticConfiguration().setValidator(new Java9Validator());
+```
+
+* 862 552 "_" is an illegal identifier on source level 9.
+* 869 867 109 855 857 smaller improvements and fixes
+
+Version 3.1.2
+------------------
+Beta: `TreeStructureVisitor`, `ConcreteSyntaxModel`, and `LexicalPreservingPrinter`.
+
+* 594 849 831 a validation framework was introduced to inform about problems in the AST without needing to change the grammar,
+and without requiring parsing code.
+It is open for extension by users.
+* 852 853 826 832 846 839 smaller improvements and fixes
+
+Version 3.1.1
+------------------
+Beta: `TreeStructureVisitor`, `ConcreteSyntaxModel`, and `LexicalPreservingPrinter`.
+
+* 654 124 lexical preservation (printing source code with the same formatting it had when parsing) has been added.
+    Thank you @ftomassetti for a lot of work! 
+* 554 800 first (big) step towards Java 9 support: JavaParser can read project Jigsaw module definitions.
+* 795 786 751 extend the TreeVisitor with more traversal options. Thanks @ryan-beckett!
+* 791 `GenericListVisitorAdapter` has been added which collects its results in a list. Thanks @Gottox!
+* 815 798 797 813 clean up Problem text
+* 819 818 817 816 441 809 808 807 fix various absurd annotation related issues. 
+* 777 805 802 796 790 792 793 781 784 785 783 782 779 357 799 763 smaller improvements and fixes
+
+Version 3.1.0
+------------------
+Beta: `TreeStructureVisitor` and `ConcreteSyntaxModel`.
+
+* 705 755 Add the concrete syntax model, which will give you information about the exact syntax a certain nodes matches.
+
+* 777 smaller improvements and fixes
+
+Version 3.1.0-beta.2
+------------------
+This version is a beta because `TreeStructureVisitor` is not in its definite state yet.
+
+* 762 761 772 merge `javaparser-metamodel` and `javaparser-generator-utils` into `javaparser-core`.
+* 766 the `ModifierVisitor` is now created by a code generator. Its behaviour has been made logical, and may give different results than before.
+* 755 `ConstructorDeclaration` and `MethodDeclaration` now share a parent: `CallableDeclaration`
+* 687 759 773 769 768 767 765 759 smaller improvements and fixes
+
+Version 3.1.0-beta.1
+------------------
+This version is a beta because there are a lot of new features that may still change.
+
+This version needs a minor version increase because of a backwards compatability issue: 
+* 719 `getJavadoc`, `getJavadocComment` and `getComment` could return null. Our promise was to return `Optional`, so that is what they do now.
+
+New:
+* 658 718 736 737 we have created a metamodel.
+It gives information about the structure of the various AST nodes, as if you are introspecting them.
+You can find it in `javaparser-metamodel`, the main class is `JavaParserMetaModel`
+* 353 365 visitors are no longer hand made, they are now generated from the metamodel. This should make them 100% reliable.
+Affected visitors are: `GenericVisitorAdapter`, `EqualsVisitor`, `VoidVisitorAdapter`, `VoidVisitor`, `GenericVisitor`, `HashCodeVisitor`, `CloneVisitor`.
+
+If you want to generate your own visitors, you can use the `VisitorGenerator` class from `javaparser-core-generators`
+
+If you want to reuse the code generation utilities, look at module `javaparser-generator-utils` - there is a very useful `SourceRoot` class in there that takes away a lot of file management troubles.
+* 538 735 `TreeStructureVisitor` has been added, which should be considered beta.
+* 220 733 717 749 745 750 743 748 666 732 746 734 733 smaller improvements and fixes
+
+Version 3.0.1
+------------------
+* 699 433 325 Javadoc can now be parsed
+* 703 696 added NodeWithOptionalScope
+* 702 FieldAccessExpr now implements NodeWithSimpleName, *which means that "field" has been renamed to "name"*
+* 707 706 improve range of array types and levels
+* 709 smaller improvements and fixes
+
+Version 3.0.0
+------------------
+* 695 697 689 680 693 691 682 690 677 679 688 684 683 smaller improvements and fixes
+
+Version 3.0.0-RC.4
+------------------
+* 668 669 TypeDeclarationStmt became LocalClassDeclarationStmt
+* 347 665 every node now has some documentation
+* 660 670 673 four types of import declaration have been merged back into the old ImportDeclaration
+* 659 The pretty printer can now take customized visitors 
+* 650 671 672 674 524 smaller improvements and fixes
+
+Version 3.0.0-RC.3
+------------------
+* 639 622 632 657 656 652 653 647 648 645 194 643 630 624 628 627 626 625 623 cleanups, small fixes, and general housekeeping
+
+Version 3.0.0-RC.2
+------------------
+* 593 EmptyImportDeclaration and NonEmptyImportDeclaration have been removed
+* 612 VariableDeclaratorId has been removed. It has been substituted by "SimpleName name"
+* 614 617 the list of tokens has been linearized and simplified
+* 615 support for arrays has once more been changed. See [the issue](https://github.com/javaparser/javaparser/issues/592) 
+* 580 453 380 618 580 611 610 424 608 smaller improvements and fixes
+
+Version 3.0.0-RC.1
+------------------
+* 499 601 renames many fields to be more consistent
+* 596 605 602 604 smaller improvements and fixes
+
+Version 3.0.0-alpha.11
+------------------
+* 547 595 Node.range is now using Optional instead of Range.UNKNOWN
+* 584 588 548 585 bug fixes and improvements
+
+Version 3.0.0-alpha.10
+------------------
+* 578 579 577 575 290 570 568 567 562 564 551 bug fixes and improvements
+
+Version 3.0.0-alpha.9
+------------------
+* 403 358 549 Make all names nodes: either SimpleName or Name. This makes every name in the AST visitable. NameExpr is now a wrapper to use SimpleName in an expression.
+* 516 536 use Optional<> for return values.
+* 556 557 558 550 small improvements and fixes.
+* 560 559 make nodes observable.
+
+Version 3.0.0-alpha.8
+------------------
+* 344 529 turn DumpVisitor into an official PrettyPrinter
+* 532 508 427 530 531 513 528 cleanups
+
+Version 3.0.0-alpha.7
+------------------
+* 515 roll back attempt at using Optional
+* 522 504 make NodeList not a Node (restores parent/children behaviour to before alpha.4)
+* 527 526 rename getChildrenNodes to getChildNodes
+* 525 495 520 bug fix
+
+Version 3.0.0-alpha.6
+------------------
+* 503 modified ImportDeclaration hierarchy to have getters for static and "asterisk" again
+* 506 bug fix
+
+Version 3.0.0-alpha.5
+------------------
+* 451 null is no longer allowed in the AST. [See last post in issue](https://github.com/javaparser/javaparser/issues/451)
+* 501 421 420 316 use a special type of list for nodes: NodeList. [See last post in issue](https://github.com/javaparser/javaparser/issues/421)
+
+Version 3.0.0-alpha.4
+------------------
+* 463 471 nodes can now be removed easily
+* 491 import handling changed. Instead of "ImportDeclaration", we now have the four types of import as described in the JLS. [See issue](https://github.com/javaparser/javaparser/pull/491)
+* 452 355 474 494 various improvements
+* 493 492 485 Simplify the JavaParser interface
+
+Version 3.0.0-alpha.3
+------------------
+* 112 237 466 465 461 460 458 457 fundamentally changes how we deal with arrays. [It is explained in the last post here](https://github.com/javaparser/javaparser/issues/237)
+* 472 456 makes the "data" field on every node more structured.
+* 477 468 refactor TypeArguments. You will find that TypeArguments is no longer a type, it is just a list in some nodes.
+* 482 adds the "nodeTypes" packages to the osgi export.
+* 479 476 makes all setters on nodes return this so they become chainable.
+* 473 437 clean up CloneVisitor.
+
+Version 3.0.0-alpha.2
+------------------
+* 157 a new parser frontend, check https://github.com/javaparser/javaparser/pull/447 for explanations
+* 435 more builder methods like 400 and 405
+* 111 440 443 444 445 446 bugs & cleanups
+
+Version 3.0.0-alpha.1
+------------------
+* 400 405 introduce many "builder" style methods for constructing code. Thanks DeepSnowNeeL!
+* 409 remove ASTHelper (methods are now on specific Node subclasses)
+* 414 JavaParser can now be instantiated and reused. InstanceJavaParser removed
+* 418 417 411 408 bugs
+* 367 420 407 402 various cleanups
+
+Version 2.5.1
+-------------
+* 394 OSGi manifest added
+* 391 fix ModifierVisitor NullPointerException bug
+* 385 a few new parse methods
+* 386 fix dumping an empty import (a single ; after the package declaration)
+
+Version 2.5.0
+-------------
+API breaking changes:
+
+* 191: moved TreeVisitor to visitor package
+* 368, 162, 303, 302, 360: use correct type in some places.
+* 371: code is now compiled with Java 8
+* 342, 331: ModifierVisitorAdapter detects and removes broken nodes
+* 328, 270: upgrade JavaCC (use TokenMgrException now)
+Other changes:
+
+* 297: enable access to tokens.
+* 341, 361: node positions are now OO
+* 211, 373: escaping of \n \r for string literals
+* 336, 276, 141: JavaDoc support now works
+* 337, 281: reorganize the stream reading code
+* 343, 309, 332, 57: take advantage of common interfaces
+* 329, 326, 327: deal with platform issues
+* 163, 236, 252, 296, 269, 339, 321, 322, 252, 253, 293, 295: various fixes
+* 310, 311, 313, 301, 294: some code clean-ups 
+
+Version 2.4.0
+-------------
+* several fixes in DumpVisitor for bugs due to lazy initialization
+* make TypeDeclaration implements DocumentableNode directly
+* TypedNode interface introduced
+* introduce MultiBoundType
+* refactored IntersectionType and UnionType
+* refactored CatchClause
+* parsing annotations in throws declarations
+* parse orphan semicolons in import statements
+* added PackageDeclaration.getPackageName
+* solved issue with newlines in string literals
+* fixed handling of UnknownType in EqualsVisitor
+* improvements to CommentsParser
+* removing old grammar
+
+Version 2.3.0
+-------------
+* ClassOrInterfaceType implements NamedNode
+* DumpVisitor can now be extended
+* Improved documentation
+* AST: lists are now lazy initialized
+
+Version 2.1.0
+-------------
+* Features
+  * [#75 performance improvement for `PositionUtils.sortByBeginPosition`](https://github.com/javaparser/javaparser/issues/75)
+  * [#64 In getDeclarationAsString parameter names should be optional](https://github.com/javaparser/javaparser/issues/64)
+* Bugfixes
+  * [#79 Fix NPE in `ConstructorDeclaration.getDeclarationAsString`](https://github.com/javaparser/javaparser/pull/79)
+  * [#86 Add missing functions to ModifierVisitorAdapter](https://github.com/javaparser/javaparser/pull/86)
+  * [#82 set LambdaExpr as parent of its child nodes](https://github.com/javaparser/javaparser/issues/82)
+  * [#87 implement `setJavadoc` and `getJavadoc` at various classes](https://github.com/javaparser/javaparser/issues/87)
+  * [#96 Fixed encoding issue in `Javaparser.parse`](https://github.com/javaparser/javaparser/pull/96)
+  * [#85 Casting a lambda expression causes a parsing failure](https://github.com/javaparser/javaparser/issues/85)
+  * [#88 `MethodReferenceExpr` and `TypeExpr` don't set themselves as parents](https://github.com/javaparser/javaparser/issues/88)
+* Internal
+  * [#89 CommentsParser.State contains unused fields](https://github.com/javaparser/javaparser/issues/89)
+  * Switched from drone.io to [Travis](https://travis-ci.org/javaparser/javaparser)
+  * [#105 Enforce compiling the library for a certain Java version](https://github.com/javaparser/javaparser/pull/105)
+
+[Code changes](https://github.com/javaparser/javaparser/compare/javaparser-parent-2.0.0...master)
+
+Version 2.0.0
+-------------
+* support Java 8
+
+Version 1.0.8 (2010-01-17)
+-------------
+* Fixed issues:
+	* Issue 17: A refactor suggestion for AnnotationExpr and its subclasses
+	* Issue 21: Java 5 JavaParser compiled JARs
+	* Issue 22: Please use java.lang.reflect.Modifier constants in japa.parser.ast.body.ModifierSet
+	* Issue 27: Implement the "equal" method
+	* Issue 30: equals and hashCode methods
+
+Version 1.0.7 (2009-04-12)
+-------------
+* Issue 19 fixed: 
+* Tests changed to run with junit 4 
+
+Version 1.0.6 (2009-01-11)
+-------------
+* Issue 11 fixed: changed method get/setPakage to get/setPackage in the class CompilationUnit
+* Created new visitor adapter to help AST modification: ModifierVisitorAdapter
+* Changed visitor adapters to abstract  
+
+Version 1.0.5 (2008-10-26)
+-------------
+* Created simplified constructors in the nodes of the AST (without positional arguments) 
+* Created ASTHelper class with some helpful methods (more methods are still needed)
+
+Version 1.0.4 (2008-10-07)
+-------------
+* Moved to javacc 4.1.
+* The java_1_5.jj can be build alone without compilation errors
+
+Version 1.0.3 (2008-09-06)
+-------------
+* Removed SuperMemberAccessExpr class, it was no longer used
+* Removed the methods get/setTypeArgs() from ArrayCreationExpr, this node shouldn't have these methods.
+* Fixed the bug with start/end position of the nodes IntegerLiteralMinValueExpr and LongLiteralMinValueExpr  
+* The methods get/setAnnotations() from all BodyDeclaration subclasses were pushed down to BodyDeclaration class 
+
+Version 1.0.2 (2008-07-20)
+-------------
+* Issue fixed: Issue 1: Add support for editing AST nodes or create new ones
+
+Version 1.0.1 (2008-07-01)
+-------------
+* Issue fixed: Issue 5: end line and end column equal to begin line and begin column
+
+Version 1.0.0 (2008-06-25)
+-------------
+* Changed version numbering, starting version 1.0.0
+* Javadoc done for packages:
+    * japa.parser
+    * japa.parser.ast
+* Corrected bug when parsing in multithread: 
+    * JavaParser.setCacheParser(false) must be called before to use the parser concurrent 
+
+2008-06-19
+-------------
+* No code changes, added binary distribution to download page 
+
+2008-06-11
+-------------
+* Bug corrected: NPE in VoidVisitorAdapter 
+	* http://code.google.com/p/javaparser/issues/detail?id=2
+
+2008-06-09
+-------------
+* Added Adapters for de visitors
+
+2008-05-28
+-------------
+* This project now is published at Google Code:
+	* http://code.google.com/p/javaparser/
+
+2008-05-25
+-------------
+* Added support for comments and javadoc to the tree. 
+	* Javadocs are stored directly to members (BodyDeclaration and all deriveds (classes, methods, fields, etc.)), accessible by the method getJavadoc().
+	* All comments are stored in the CompilationUnit, accessible by the method getComments().
+
+2008-04-01
+-------------
+* Changed all nodes public attributes to be private and created getters to access them
+* Changed the methods of the Node getLine e getColumn to getBeginLine and getBeginColumn
+* Added the methods getEndLine and getEndColumn to the Node class (works only in the BlockNode)
+
+2007-12-22
+-------------
+* Corrected ConditionalExpression bug
+
+2007-10-21
+-------------
+* Added LGPL License
+
+2007-10-21
+-------------
+* Bugs corrected:  
+  * Created PackageDeclaration member of CompilationUnit to add suport for annotations in the package declaration
+  * Parameterized anonymous constructor invocation
+  * Explicit constructor invotation Type Arguments
+  * ctrl+z ("\u001A") ar end of compilation unit
+
+2007-10-09
+-------------
+* EnumConstantDeclaration annotation support corrected
+* Parssing Java Unicode escape characters suport added
+
+2007-10-03
+-------------
+* Bug corrected: "MotifComboPopup.this.super()" statement was generating parser error
+	                    
+2007-10-01
+-------------
+* Bug corrected: Casting signed primitive values
+```
+	double d = (double) -1;
+	                    ^
+```
+2007-08-06
+-------------
+* Bug with the single line comments in the final of the unit corrected
+
+2007-07-31
+-------------
+* Fixed the bug with the following expression:  `Class c = (int.class);`
+
+2007-06-26
+-------------
+* Bug fixes from Leon Poyyayil work
+	* suport for hex floating point
+	* unicode digits in indentifier 
+	* MemberValueArrayInitializer
+
+2007-03-09
+-------------
+* Long and Integer literal MIN_VALUE bug	
+
+2007-02-24
+-------------
+* '\0' bug fixed	
+
+2007-02-01
+-------------
+* Many bug fixes
+* Added line/column to nodes
diff --git a/dev-files/JavaParser-eclipse.xml b/dev-files/JavaParser-eclipse.xml
new file mode 100644
index 0000000..853811c
--- /dev/null
+++ b/dev-files/JavaParser-eclipse.xml
@@ -0,0 +1,295 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<profiles version="12">
+<profile kind="CodeFormatterProfile" name="JavaParser" version="12">
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
+<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
+<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="119"/>
+<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="18"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
+<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
+<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
+<setting id="org.eclipse.jdt.core.compiler.source" value="1.8"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.8"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="18"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.8"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="false"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
+<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
+<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
+<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
+</profile>
+</profiles>
diff --git a/dev-files/JavaParser-idea.xml b/dev-files/JavaParser-idea.xml
new file mode 100644
index 0000000..9745dc8
--- /dev/null
+++ b/dev-files/JavaParser-idea.xml
@@ -0,0 +1,38 @@
+<code_scheme name="JavaParser">
+  <option name="OTHER_INDENT_OPTIONS">
+    <value>
+      <option name="INDENT_SIZE" value="4" />
+      <option name="CONTINUATION_INDENT_SIZE" value="8" />
+      <option name="TAB_SIZE" value="4" />
+      <option name="USE_TAB_CHARACTER" value="true" />
+      <option name="SMART_TABS" value="true" />
+      <option name="LABEL_INDENT_SIZE" value="0" />
+      <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+      <option name="USE_RELATIVE_INDENTS" value="false" />
+    </value>
+  </option>
+  <option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
+  <option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
+  <option name="WRAP_COMMENTS" value="true" />
+  <XML>
+    <option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
+  </XML>
+  <codeStyleSettings language="JAVA">
+    <option name="RIGHT_MARGIN" value="120" />
+    <indentOptions>
+      <option name="SMART_TABS" value="true" />
+    </indentOptions>
+  </codeStyleSettings>
+  <codeStyleSettings language="Scala">
+    <indentOptions>
+      <option name="USE_TAB_CHARACTER" value="true" />
+      <option name="SMART_TABS" value="true" />
+    </indentOptions>
+  </codeStyleSettings>
+  <codeStyleSettings language="XML">
+    <indentOptions>
+      <option name="USE_TAB_CHARACTER" value="true" />
+      <option name="SMART_TABS" value="true" />
+    </indentOptions>
+  </codeStyleSettings>
+</code_scheme>
\ No newline at end of file
diff --git a/javaparser-core-generators/javaparser-core-generators.iml b/javaparser-core-generators/javaparser-core-generators.iml
new file mode 100644
index 0000000..7843639
--- /dev/null
+++ b/javaparser-core-generators/javaparser-core-generators.iml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
+    <output url="file://$MODULE_DIR$/target/classes" />
+    <output-test url="file://$MODULE_DIR$/target/test-classes" />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+      <excludeFolder url="file://$MODULE_DIR$/target" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="javaparser-core" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/javaparser-core-generators/pom.xml b/javaparser-core-generators/pom.xml
new file mode 100644
index 0000000..58eecf8
--- /dev/null
+++ b/javaparser-core-generators/pom.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>javaparser-parent</artifactId>
+        <groupId>com.github.javaparser</groupId>
+        <version>3.5.16-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>javaparser-core-generators</artifactId>
+    <description>A code generator framework, and the generators for javaparser-core</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.github.javaparser</groupId>
+            <artifactId>javaparser-core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>run-core-generators</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>exec-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>generate-javaparser-core</id>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>java</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                        <configuration>
+                            <classpathScope>test</classpathScope>
+                            <mainClass>com.github.javaparser.generator.core.CoreGenerator</mainClass>
+                            <arguments>
+                                <argument>${project.basedir}</argument>
+                            </arguments>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/Generator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/Generator.java
new file mode 100644
index 0000000..f7860b0
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/Generator.java
@@ -0,0 +1,104 @@
+package com.github.javaparser.generator;
+
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.body.CallableDeclaration;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.expr.StringLiteralExpr;
+import com.github.javaparser.ast.nodeTypes.NodeWithAnnotations;
+import com.github.javaparser.utils.SourceRoot;
+
+import javax.annotation.Generated;
+import java.util.List;
+
+import static com.github.javaparser.ast.NodeList.toNodeList;
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+
+/**
+ * A general pattern that the generators in this module will follow.
+ */
+public abstract class Generator {
+    protected final SourceRoot sourceRoot;
+
+    protected Generator(SourceRoot sourceRoot) {
+        this.sourceRoot = sourceRoot;
+    }
+
+    public abstract void generate() throws Exception;
+
+    protected <T extends Node & NodeWithAnnotations<?>> void annotateGenerated(T node) {
+        annotate(node, Generated.class, new StringLiteralExpr(getClass().getName()));
+    }
+
+    protected <T extends Node & NodeWithAnnotations<?>> void annotateSuppressWarnings(T node) {
+        annotate(node, SuppressWarnings.class, new StringLiteralExpr("unchecked"));
+    }
+
+    protected void annotateOverridden(MethodDeclaration method) {
+        annotate(method, Override.class, null);
+    }
+
+    private <T extends Node & NodeWithAnnotations<?>> void annotate(T node, Class<?> annotation, Expression content) {
+        node.setAnnotations(
+                node.getAnnotations().stream()
+                        .filter(a -> !a.getNameAsString().equals(annotation.getSimpleName()))
+                        .collect(toNodeList()));
+
+        if (content != null) {
+            node.addSingleMemberAnnotation(annotation.getSimpleName(), content);
+        } else {
+            node.addMarkerAnnotation(annotation.getSimpleName());
+        }
+        node.tryAddImportToParentCompilationUnit(annotation);
+    }
+
+    /**
+     * Utility method that looks for a method or constructor with an identical signature as "callable" and replaces it
+     * with callable. If not found, adds callable. When the new callable has no javadoc, any old javadoc will be kept.
+     */
+    protected void addOrReplaceWhenSameSignature(ClassOrInterfaceDeclaration containingClassOrInterface, CallableDeclaration<?> callable) {
+        addMethod(containingClassOrInterface, callable, () -> containingClassOrInterface.addMember(callable));
+    }
+
+    /**
+     * Utility method that looks for a method or constructor with an identical signature as "callable" and replaces it
+     * with callable. If not found, fails. When the new callable has no javadoc, any old javadoc will be kept. The
+     * method or constructor is annotated with the generator class.
+     */
+    protected void replaceWhenSameSignature(ClassOrInterfaceDeclaration containingClassOrInterface, CallableDeclaration<?> callable) {
+        addMethod(containingClassOrInterface, callable,
+                () -> {
+                    throw new AssertionError(f("Wanted to regenerate a method with signature %s in %s, but it wasn't there.", callable.getSignature(), containingClassOrInterface.getNameAsString()));
+                });
+    }
+
+    private void addMethod(
+            ClassOrInterfaceDeclaration containingClassOrInterface,
+            CallableDeclaration<?> callable,
+            Runnable onNoExistingMethod) {
+        List<CallableDeclaration<?>> existingCallables = containingClassOrInterface.getCallablesWithSignature(callable.getSignature());
+        if (existingCallables.isEmpty()) {
+            onNoExistingMethod.run();
+            return;
+        }
+        if (existingCallables.size() > 1) {
+            throw new AssertionError(f("Wanted to regenerate a method with signature %s in %s, but found more than one.", callable.getSignature(), containingClassOrInterface.getNameAsString()));
+        }
+        final CallableDeclaration<?> existingCallable = existingCallables.get(0);
+        callable.setJavadocComment(callable.getJavadocComment().orElse(existingCallable.getJavadocComment().orElse(null)));
+        annotateGenerated(callable);
+        containingClassOrInterface.getMembers().replace(existingCallable, callable);
+    }
+
+    /**
+     * Removes all methods from containingClassOrInterface that have the same signature as callable. This is not used by
+     * any code, but it is useful when changing a generator and you need to get rid of a set of outdated methods.
+     */
+    protected void removeMethodWithSameSignature(ClassOrInterfaceDeclaration containingClassOrInterface, CallableDeclaration<?> callable) {
+        for (CallableDeclaration<?> existingCallable : containingClassOrInterface.getCallablesWithSignature(callable.getSignature())) {
+            containingClassOrInterface.remove(existingCallable);
+        }
+    }
+
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/NodeGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/NodeGenerator.java
new file mode 100644
index 0000000..18ab60d
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/NodeGenerator.java
@@ -0,0 +1,46 @@
+package com.github.javaparser.generator;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.CallableDeclaration;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import com.github.javaparser.utils.Log;
+import com.github.javaparser.utils.Pair;
+import com.github.javaparser.utils.SourceRoot;
+
+import java.io.IOException;
+import java.util.List;
+
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+
+/**
+ * Makes it easier to generate code in the core AST nodes. The generateNode method will get every node type passed to
+ * it, ready for modification.
+ */
+public abstract class NodeGenerator extends Generator {
+    protected NodeGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot);
+    }
+
+    public final void generate() throws Exception {
+        Log.info("Running %s", getClass().getSimpleName());
+        for (BaseNodeMetaModel nodeMetaModel : JavaParserMetaModel.getNodeMetaModels()) {
+            Pair<CompilationUnit, ClassOrInterfaceDeclaration> result = parseNode(nodeMetaModel);
+            generateNode(nodeMetaModel, result.a, result.b);
+        }
+        after();
+    }
+
+    protected Pair<CompilationUnit, ClassOrInterfaceDeclaration> parseNode(BaseNodeMetaModel nodeMetaModel) {
+        CompilationUnit nodeCu = sourceRoot.parse(nodeMetaModel.getPackageName(), nodeMetaModel.getTypeName() + ".java");
+        ClassOrInterfaceDeclaration nodeCoid = nodeCu.getClassByName(nodeMetaModel.getTypeName()).orElseThrow(() -> new AssertionError("Can't find class"));
+        return new Pair<>(nodeCu, nodeCoid);
+    }
+
+    protected void after() throws Exception {
+
+    }
+
+    protected abstract void generateNode(BaseNodeMetaModel nodeMetaModel, CompilationUnit nodeCu, ClassOrInterfaceDeclaration nodeCoid) throws Exception;
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/VisitorGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/VisitorGenerator.java
new file mode 100644
index 0000000..16b5ef4
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/VisitorGenerator.java
@@ -0,0 +1,82 @@
+package com.github.javaparser.generator;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.expr.MarkerAnnotationExpr;
+import com.github.javaparser.ast.expr.Name;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import com.github.javaparser.utils.Log;
+import com.github.javaparser.utils.SourceRoot;
+
+import java.util.Optional;
+
+import static com.github.javaparser.ast.Modifier.PUBLIC;
+
+/**
+ * Makes it easier to generate visitor classes.
+ * It will create missing visit methods on the fly,
+ * and will ask you to fill in the bodies of the visit methods.
+ */
+public abstract class VisitorGenerator extends Generator {
+    private final String pkg;
+    private final String visitorClassName;
+    private final String returnType;
+    private final String argumentType;
+    private final boolean createMissingVisitMethods;
+
+    protected VisitorGenerator(SourceRoot sourceRoot, String pkg, String visitorClassName, String returnType, String argumentType, boolean createMissingVisitMethods) {
+        super(sourceRoot);
+        this.pkg = pkg;
+        this.visitorClassName = visitorClassName;
+        this.returnType = returnType;
+        this.argumentType = argumentType;
+        this.createMissingVisitMethods = createMissingVisitMethods;
+    }
+
+    public final void generate() throws Exception {
+        Log.info("Running %s", getClass().getSimpleName());
+
+        final CompilationUnit compilationUnit = sourceRoot.tryToParse(pkg, visitorClassName + ".java").getResult().get();
+
+        Optional<ClassOrInterfaceDeclaration> visitorClassOptional = compilationUnit.getClassByName(visitorClassName);
+        if (!visitorClassOptional.isPresent()) {
+            visitorClassOptional = compilationUnit.getInterfaceByName(visitorClassName);
+        }
+        final ClassOrInterfaceDeclaration visitorClass = visitorClassOptional.get();
+
+        JavaParserMetaModel.getNodeMetaModels().stream()
+                .filter((baseNodeMetaModel) -> !baseNodeMetaModel.isAbstract())
+                .forEach(node -> generateVisitMethodForNode(node, visitorClass, compilationUnit));
+        after();
+    }
+
+    protected void after() throws Exception {
+
+    }
+
+    private void generateVisitMethodForNode(BaseNodeMetaModel node, ClassOrInterfaceDeclaration visitorClass, CompilationUnit compilationUnit) {
+        final Optional<MethodDeclaration> existingVisitMethod = visitorClass.getMethods().stream()
+                .filter(m -> m.getNameAsString().equals("visit"))
+                .filter(m -> m.getParameter(0).getType().toString().equals(node.getTypeName()))
+                .findFirst();
+
+        if (existingVisitMethod.isPresent()) {
+            generateVisitMethodBody(node, existingVisitMethod.get(), compilationUnit);
+        } else if (createMissingVisitMethods) {
+            MethodDeclaration newVisitMethod = visitorClass.addMethod("visit")
+                    .addParameter(node.getTypeNameGenerified(), "n")
+                    .addParameter(argumentType, "arg")
+                    .setType(returnType);
+            if (!visitorClass.isInterface()) {
+                newVisitMethod
+                        .addAnnotation(new MarkerAnnotationExpr(new Name("Override")))
+                        .addModifier(PUBLIC);
+            }
+            generateVisitMethodBody(node, newVisitMethod, compilationUnit);
+        }
+    }
+
+    protected abstract void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod, CompilationUnit compilationUnit);
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/CoreGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/CoreGenerator.java
new file mode 100644
index 0000000..c1aa5f9
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/CoreGenerator.java
@@ -0,0 +1,73 @@
+package com.github.javaparser.generator.core;
+
+import com.github.javaparser.ParserConfiguration;
+import com.github.javaparser.generator.core.node.*;
+import com.github.javaparser.generator.core.other.TokenKindGenerator;
+import com.github.javaparser.generator.core.visitor.*;
+import com.github.javaparser.utils.Log;
+import com.github.javaparser.utils.SourceRoot;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Generates all generated visitors in the javaparser-core module.
+ * Suggested usage is by running the run_core_generators.sh script.
+ * You may want to run_metamodel_generator.sh before that.
+ */
+public class CoreGenerator {
+    private static final ParserConfiguration parserConfiguration = new ParserConfiguration()
+//                                .setStoreTokens(false)
+//                                .setAttributeComments(false)
+//                                .setLexicalPreservationEnabled(true)
+            ;
+
+    public static void main(String[] args) throws Exception {
+        if (args.length != 1) {
+            throw new RuntimeException("Need 1 parameter: the JavaParser source checkout root directory.");
+        }
+        Log.setAdapter(new Log.StandardOutStandardErrorAdapter());
+        final Path root = Paths.get(args[0], "..", "javaparser-core", "src", "main", "java");
+        final SourceRoot sourceRoot = new SourceRoot(root, parserConfiguration)
+//                .setPrinter(LexicalPreservingPrinter::print)
+                ;
+
+        final Path generatedJavaCcRoot = Paths.get(args[0], "..", "javaparser-core", "target", "generated-sources", "javacc");
+        final SourceRoot generatedJavaCcSourceRoot = new SourceRoot(generatedJavaCcRoot, parserConfiguration)
+//                .setPrinter(LexicalPreservingPrinter::print)
+                ;
+
+        new CoreGenerator().run(sourceRoot, generatedJavaCcSourceRoot);
+
+        sourceRoot.saveAll();
+    }
+
+    private void run(SourceRoot sourceRoot, SourceRoot generatedJavaCcSourceRoot) throws Exception {
+        new TypeCastingGenerator(sourceRoot).generate();
+        new GenericListVisitorAdapterGenerator(sourceRoot).generate();
+        new GenericVisitorAdapterGenerator(sourceRoot).generate();
+        new GenericVisitorWithDefaultsGenerator(sourceRoot).generate();
+        new EqualsVisitorGenerator(sourceRoot).generate();
+        new ObjectIdentityEqualsVisitorGenerator(sourceRoot).generate();
+        new NoCommentEqualsVisitorGenerator(sourceRoot).generate();
+        new VoidVisitorAdapterGenerator(sourceRoot).generate();
+        new VoidVisitorGenerator(sourceRoot).generate();
+        new VoidVisitorWithDefaultsGenerator(sourceRoot).generate();
+        new GenericVisitorGenerator(sourceRoot).generate();
+        new HashCodeVisitorGenerator(sourceRoot).generate();
+        new ObjectIdentityHashCodeVisitorGenerator(sourceRoot).generate();
+        new NoCommentHashCodeVisitorGenerator(sourceRoot).generate();
+        new CloneVisitorGenerator(sourceRoot).generate();
+        new ModifierVisitorGenerator(sourceRoot).generate();
+
+        new PropertyGenerator(sourceRoot).generate();
+        new RemoveMethodGenerator(sourceRoot).generate();
+        new ReplaceMethodGenerator(sourceRoot).generate();
+        new CloneGenerator(sourceRoot).generate();
+        new GetMetaModelGenerator(sourceRoot).generate();
+        new MainConstructorGenerator(sourceRoot).generate();
+        new FinalGenerator(sourceRoot).generate();
+        new AcceptGenerator(sourceRoot).generate();
+        new TokenKindGenerator(sourceRoot, generatedJavaCcSourceRoot).generate();
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/AcceptGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/AcceptGenerator.java
new file mode 100644
index 0000000..9ab2bf3
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/AcceptGenerator.java
@@ -0,0 +1,34 @@
+package com.github.javaparser.generator.core.node;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.visitor.GenericVisitor;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+import com.github.javaparser.generator.NodeGenerator;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.utils.SourceRoot;
+
+import static com.github.javaparser.JavaParser.parseBodyDeclaration;
+
+public class AcceptGenerator extends NodeGenerator {
+    private final MethodDeclaration genericAccept;
+    private final MethodDeclaration voidAccept;
+
+    public AcceptGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot);
+        genericAccept = parseBodyDeclaration("@Override public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) { return v.visit(this, arg); }").asMethodDeclaration();
+        voidAccept = parseBodyDeclaration("@Override public <A> void accept(final VoidVisitor<A> v, final A arg) { v.visit(this, arg); }").asMethodDeclaration();
+    }
+
+    @Override
+    protected void generateNode(BaseNodeMetaModel nodeMetaModel, CompilationUnit nodeCu, ClassOrInterfaceDeclaration nodeCoid) {
+        if(nodeMetaModel.isAbstract()){
+            return;
+        }
+        nodeCu.addImport(GenericVisitor.class);
+        nodeCu.addImport(VoidVisitor.class);
+        addOrReplaceWhenSameSignature(nodeCoid, genericAccept);
+        addOrReplaceWhenSameSignature(nodeCoid, voidAccept);
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/CloneGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/CloneGenerator.java
new file mode 100644
index 0000000..6a788b4
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/CloneGenerator.java
@@ -0,0 +1,29 @@
+package com.github.javaparser.generator.core.node;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.visitor.CloneVisitor;
+import com.github.javaparser.generator.NodeGenerator;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.utils.SourceRoot;
+
+import static com.github.javaparser.JavaParser.parseBodyDeclaration;
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+
+public class CloneGenerator extends NodeGenerator {
+    public CloneGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot);
+    }
+
+    @Override
+    protected void generateNode(BaseNodeMetaModel nodeMetaModel, CompilationUnit nodeCu, ClassOrInterfaceDeclaration nodeCoid) {
+        nodeCu.addImport(CloneVisitor.class);
+        MethodDeclaration cloneMethod = (MethodDeclaration) parseBodyDeclaration(f(
+                "@Override public %s clone() { return (%s) accept(new CloneVisitor(), null); }",
+                nodeMetaModel.getTypeNameGenerified(),
+                nodeMetaModel.getTypeNameGenerified()
+        ));
+        addOrReplaceWhenSameSignature(nodeCoid, cloneMethod);
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/FinalGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/FinalGenerator.java
new file mode 100644
index 0000000..8e8cef2
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/FinalGenerator.java
@@ -0,0 +1,18 @@
+package com.github.javaparser.generator.core.node;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.generator.NodeGenerator;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.utils.SourceRoot;
+
+public class FinalGenerator extends NodeGenerator {
+    public FinalGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot);
+    }
+
+    @Override
+    protected void generateNode(BaseNodeMetaModel nodeMetaModel, CompilationUnit nodeCu, ClassOrInterfaceDeclaration nodeCoid) {
+        nodeCoid.setFinal(!nodeMetaModel.isAbstract());
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/GetMetaModelGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/GetMetaModelGenerator.java
new file mode 100644
index 0000000..750c52b
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/GetMetaModelGenerator.java
@@ -0,0 +1,30 @@
+package com.github.javaparser.generator.core.node;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.generator.NodeGenerator;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import com.github.javaparser.utils.SourceRoot;
+
+import static com.github.javaparser.JavaParser.parseBodyDeclaration;
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+
+public class GetMetaModelGenerator extends NodeGenerator {
+    public GetMetaModelGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot);
+    }
+
+    @Override
+    protected void generateNode(BaseNodeMetaModel nodeMetaModel, CompilationUnit nodeCu, ClassOrInterfaceDeclaration nodeCoid) {
+        final MethodDeclaration getMetaModelMethod = (MethodDeclaration) parseBodyDeclaration(f("%s public %s getMetaModel() { return JavaParserMetaModel.%s; }",
+                nodeMetaModel.isRootNode() ? "" : "@Override",
+                nodeMetaModel.getClass().getSimpleName(),
+                nodeMetaModel.getMetaModelFieldName()));
+
+        addOrReplaceWhenSameSignature(nodeCoid, getMetaModelMethod);
+        nodeCu.addImport(nodeMetaModel.getClass().getName());
+        nodeCu.addImport(JavaParserMetaModel.class);
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/MainConstructorGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/MainConstructorGenerator.java
new file mode 100644
index 0000000..8f71589
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/MainConstructorGenerator.java
@@ -0,0 +1,54 @@
+package com.github.javaparser.generator.core.node;
+
+import com.github.javaparser.TokenRange;
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.ConstructorDeclaration;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.generator.NodeGenerator;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.PropertyMetaModel;
+import com.github.javaparser.utils.SeparatedItemStringBuilder;
+import com.github.javaparser.utils.SourceRoot;
+
+import static com.github.javaparser.JavaParser.parseExplicitConstructorInvocationStmt;
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+
+public class MainConstructorGenerator extends NodeGenerator {
+    public MainConstructorGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot);
+    }
+
+    @Override
+    protected void generateNode(BaseNodeMetaModel nodeMetaModel, CompilationUnit nodeCu, ClassOrInterfaceDeclaration nodeCoid) {
+        if (nodeMetaModel.is(Node.class)) {
+            return;
+        }
+        ConstructorDeclaration constructor = new ConstructorDeclaration()
+                .setPublic(true)
+                .setName(nodeCoid.getNameAsString())
+                .addParameter(TokenRange.class, "tokenRange")
+                .setJavadocComment("\n     * This constructor is used by the parser and is considered private.\n     ");
+
+        BlockStmt body = constructor.getBody();
+
+        SeparatedItemStringBuilder superCall = new SeparatedItemStringBuilder("super(", ", ", ");");
+        superCall.append("tokenRange");
+        for (PropertyMetaModel parameter : nodeMetaModel.getConstructorParameters()) {
+            constructor.addParameter(parameter.getTypeNameForSetter(), parameter.getName());
+            if (nodeMetaModel.getDeclaredPropertyMetaModels().contains(parameter)) {
+                body.addStatement(f("%s(%s);", parameter.getSetterMethodName(), parameter.getName()));
+            } else {
+                superCall.append(parameter.getName());
+            }
+        }
+
+        body.getStatements().addFirst(parseExplicitConstructorInvocationStmt(superCall.toString()));
+
+        body.addStatement("customInitialization();");
+
+        addOrReplaceWhenSameSignature(nodeCoid, constructor);
+        nodeCu.addImport(TokenRange.class);
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/PropertyGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/PropertyGenerator.java
new file mode 100644
index 0000000..9ac69ed
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/PropertyGenerator.java
@@ -0,0 +1,145 @@
+package com.github.javaparser.generator.core.node;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.EnumConstantDeclaration;
+import com.github.javaparser.ast.body.EnumDeclaration;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.generator.NodeGenerator;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import com.github.javaparser.metamodel.PropertyMetaModel;
+import com.github.javaparser.utils.SourceRoot;
+
+import java.util.*;
+
+import static com.github.javaparser.JavaParser.parseType;
+import static com.github.javaparser.ast.Modifier.FINAL;
+import static com.github.javaparser.ast.Modifier.PUBLIC;
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+import static com.github.javaparser.utils.Utils.camelCaseToScreaming;
+
+public class PropertyGenerator extends NodeGenerator {
+
+    private final Map<String, PropertyMetaModel> declaredProperties = new HashMap<>();
+    private final Map<String, PropertyMetaModel> derivedProperties = new HashMap<>();
+
+    public PropertyGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot);
+    }
+
+    @Override
+    protected void generateNode(BaseNodeMetaModel nodeMetaModel, CompilationUnit nodeCu, ClassOrInterfaceDeclaration nodeCoid) {
+        for (PropertyMetaModel property : nodeMetaModel.getDeclaredPropertyMetaModels()) {
+            generateGetter(nodeMetaModel, nodeCoid, property);
+            generateSetter(nodeMetaModel, nodeCoid, property);
+        }
+        nodeMetaModel.getDerivedPropertyMetaModels().forEach(p -> derivedProperties.put(p.getName(), p));
+    }
+
+    private void generateSetter(BaseNodeMetaModel nodeMetaModel, ClassOrInterfaceDeclaration nodeCoid, PropertyMetaModel property) {
+        final String name = property.getName();
+        // Fill body
+        final String observableName = camelCaseToScreaming(name.startsWith("is") ? name.substring(2) : name);
+        declaredProperties.put(observableName, property);
+
+        if (property == JavaParserMetaModel.nodeMetaModel.commentPropertyMetaModel) {
+            // Node.comment has a very specific setter that we shouldn't overwrite.
+            return;
+        }
+
+        final MethodDeclaration setter = new MethodDeclaration(EnumSet.of(PUBLIC), parseType(property.getContainingNodeMetaModel().getTypeNameGenerified()), property.getSetterMethodName());
+        if (property.getContainingNodeMetaModel().hasWildcard()) {
+            setter.setType(parseType("T"));
+        }
+        setter.addAndGetParameter(property.getTypeNameForSetter(), property.getName())
+                .addModifier(FINAL);
+
+        final BlockStmt body = setter.getBody().get();
+        body.getStatements().clear();
+
+        if (property.isRequired()) {
+            Class<?> type = property.getType();
+            if (property.isNonEmpty() && property.isSingular()) {
+                body.addStatement(f("assertNonEmpty(%s);", name));
+            } else if (type != boolean.class && type != int.class) {
+                body.addStatement(f("assertNotNull(%s);", name));
+            }
+        }
+        body.addStatement(f("if (%s == this.%s) { return (%s) this; }", name, name, setter.getType()));
+
+        body.addStatement(f("notifyPropertyChange(ObservableProperty.%s, this.%s, %s);", observableName, name, name));
+        if (property.isNode()) {
+            body.addStatement(f("if (this.%s != null) this.%s.setParentNode(null);", name, name));
+        }
+        body.addStatement(f("this.%s = %s;", name, name));
+        if (property.isNode()) {
+            body.addStatement(f("setAsParentNodeOf(%s);", name));
+        }
+        if (property.getContainingNodeMetaModel().hasWildcard()) {
+            body.addStatement(f("return (T) this;"));
+        } else {
+            body.addStatement(f("return this;"));
+        }
+        replaceWhenSameSignature(nodeCoid, setter);
+        if (property.getContainingNodeMetaModel().hasWildcard()) {
+            annotateSuppressWarnings(setter);
+        }
+    }
+
+    private void generateGetter(BaseNodeMetaModel nodeMetaModel, ClassOrInterfaceDeclaration nodeCoid, PropertyMetaModel property) {
+        final MethodDeclaration getter = new MethodDeclaration(EnumSet.of(PUBLIC), parseType(property.getTypeNameForGetter()), property.getGetterMethodName());
+        final BlockStmt body = getter.getBody().get();
+        body.getStatements().clear();
+        if (property.isOptional()) {
+            body.addStatement(f("return Optional.ofNullable(%s);", property.getName()));
+        } else {
+            body.addStatement(f("return %s;", property.getName()));
+        }
+        replaceWhenSameSignature(nodeCoid, getter);
+    }
+
+    private void generateObservableProperty(EnumDeclaration observablePropertyEnum, PropertyMetaModel property, boolean derived) {
+        boolean isAttribute = !Node.class.isAssignableFrom(property.getType());
+        String name = property.getName();
+        String constantName = camelCaseToScreaming(name.startsWith("is") ? name.substring(2) : name);
+        EnumConstantDeclaration enumConstantDeclaration = observablePropertyEnum.addEnumConstant(constantName);
+        if (isAttribute) {
+            if (property.isEnumSet()) {
+                enumConstantDeclaration.addArgument("Type.MULTIPLE_ATTRIBUTE");
+            } else {
+                enumConstantDeclaration.addArgument("Type.SINGLE_ATTRIBUTE");
+            }
+        } else {
+            if (property.isNodeList()) {
+                enumConstantDeclaration.addArgument("Type.MULTIPLE_REFERENCE");
+            } else {
+                enumConstantDeclaration.addArgument("Type.SINGLE_REFERENCE");
+            }
+        }
+        if (derived) {
+            enumConstantDeclaration.addArgument("true");
+        }
+    }
+
+    @Override
+    protected void after() throws Exception {
+        CompilationUnit observablePropertyCu = sourceRoot.tryToParse("com.github.javaparser.ast.observer", "ObservableProperty.java").getResult().get();
+        EnumDeclaration observablePropertyEnum = observablePropertyCu.getEnumByName("ObservableProperty").get();
+        observablePropertyEnum.getEntries().clear();
+        List<String> observablePropertyNames = new LinkedList<>(declaredProperties.keySet());
+        observablePropertyNames.sort(String::compareTo);
+        for (String propName : observablePropertyNames) {
+            generateObservableProperty(observablePropertyEnum, declaredProperties.get(propName), false);
+        }
+        List<String> derivedPropertyNames = new LinkedList<>(derivedProperties.keySet());
+        derivedPropertyNames.sort(String::compareTo);
+        for (String propName : derivedPropertyNames) {
+            generateObservableProperty(observablePropertyEnum, derivedProperties.get(propName), true);
+        }
+        observablePropertyEnum.addEnumConstant("RANGE");
+        observablePropertyEnum.addEnumConstant("COMMENTED_NODE");
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/RemoveMethodGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/RemoveMethodGenerator.java
new file mode 100644
index 0000000..64d5898
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/RemoveMethodGenerator.java
@@ -0,0 +1,87 @@
+package com.github.javaparser.generator.core.node;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.generator.NodeGenerator;
+import com.github.javaparser.utils.SourceRoot;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.PropertyMetaModel;
+
+import static com.github.javaparser.JavaParser.*;
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+import static com.github.javaparser.utils.Utils.capitalize;
+
+
+public class RemoveMethodGenerator extends NodeGenerator {
+    public RemoveMethodGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot);
+    }
+
+    @Override
+    protected void generateNode(BaseNodeMetaModel nodeMetaModel, CompilationUnit nodeCu, ClassOrInterfaceDeclaration nodeCoid) {
+        MethodDeclaration removeNodeMethod = (MethodDeclaration) parseBodyDeclaration("public boolean remove(Node node) {}");
+        nodeCu.addImport(Node.class);
+        nodeMetaModel.getSuperNodeMetaModel().ifPresent(s -> annotateOverridden(removeNodeMethod));
+
+        final BlockStmt body = removeNodeMethod.getBody().get();
+
+        body.addStatement("if (node == null) return false;");
+
+        for (PropertyMetaModel property : nodeMetaModel.getDeclaredPropertyMetaModels()) {
+            if (!property.isNode()) {
+                continue;
+            }
+            String check;
+            if (property.isNodeList()) {
+                check = nodeListCheck(property);
+            } else {
+                if (property.isRequired()) {
+                    continue;
+                }
+                String removeAttributeMethodName = generateRemoveMethodForAttribute(nodeCoid, nodeMetaModel, property);
+                check = attributeCheck(property, removeAttributeMethodName);
+            }
+            if (property.isOptional()) {
+                check = f("if (%s != null) { %s }", property.getName(), check);
+            }
+            body.addStatement(check);
+        }
+        if (nodeMetaModel.getSuperNodeMetaModel().isPresent()) {
+            body.addStatement("return super.remove(node);");
+        } else {
+            body.addStatement("return false;");
+        }
+        
+        addOrReplaceWhenSameSignature(nodeCoid, removeNodeMethod);
+    }
+
+    private String attributeCheck(PropertyMetaModel property, String removeAttributeMethodName) {
+        return f("if (node == %s) {" +
+                "    %s();" +
+                "    return true;\n" +
+                "}", property.getName(), removeAttributeMethodName);
+    }
+
+    private String nodeListCheck(PropertyMetaModel property) {
+        return f("for (int i = 0; i < %s.size(); i++) {" +
+                "  if (%s.get(i) == node) {" +
+                "    %s.remove(i);" +
+                "    return true;" +
+                "  }" +
+                "}", property.getName(), property.getName(), property.getName());
+    }
+
+    private String generateRemoveMethodForAttribute(ClassOrInterfaceDeclaration nodeCoid, BaseNodeMetaModel nodeMetaModel, PropertyMetaModel property) {
+        final String methodName = "remove" + capitalize(property.getName());
+        final MethodDeclaration removeMethod = (MethodDeclaration) parseBodyDeclaration(f("public %s %s() {}", nodeMetaModel.getTypeName(), methodName));
+
+        final BlockStmt block = removeMethod.getBody().get();
+        block.addStatement(f("return %s((%s) null);", property.getSetterMethodName(), property.getTypeNameForSetter()));
+
+        addOrReplaceWhenSameSignature(nodeCoid, removeMethod);
+        return methodName;
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/ReplaceMethodGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/ReplaceMethodGenerator.java
new file mode 100644
index 0000000..f1f9d3f
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/ReplaceMethodGenerator.java
@@ -0,0 +1,71 @@
+package com.github.javaparser.generator.core.node;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.generator.NodeGenerator;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.PropertyMetaModel;
+import com.github.javaparser.utils.SourceRoot;
+
+import static com.github.javaparser.JavaParser.parseBodyDeclaration;
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+import static com.github.javaparser.utils.Utils.capitalize;
+
+public class ReplaceMethodGenerator extends NodeGenerator {
+    public ReplaceMethodGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot);
+    }
+
+    @Override
+    protected void generateNode(BaseNodeMetaModel nodeMetaModel, CompilationUnit nodeCu, ClassOrInterfaceDeclaration nodeCoid) {
+        MethodDeclaration replaceNodeMethod = (MethodDeclaration) parseBodyDeclaration("public boolean replace(Node node, Node replacementNode) {}");
+        nodeCu.addImport(Node.class);
+        nodeMetaModel.getSuperNodeMetaModel().ifPresent(s -> annotateOverridden(replaceNodeMethod));
+
+        final BlockStmt body = replaceNodeMethod.getBody().get();
+
+        body.addStatement("if (node == null) return false;");
+
+        for (PropertyMetaModel property : nodeMetaModel.getDeclaredPropertyMetaModels()) {
+            if (!property.isNode()) {
+                continue;
+            }
+            String check;
+            if (property.isNodeList()) {
+                check = nodeListCheck(property);
+            } else {
+                check = attributeCheck(property, property.getSetterMethodName());
+            }
+            if (property.isOptional()) {
+                check = f("if (%s != null) { %s }", property.getName(), check);
+            }
+            body.addStatement(check);
+        }
+        if (nodeMetaModel.getSuperNodeMetaModel().isPresent()) {
+            body.addStatement("return super.replace(node, replacementNode);");
+        } else {
+            body.addStatement("return false;");
+        }
+        
+        addOrReplaceWhenSameSignature(nodeCoid, replaceNodeMethod);
+    }
+
+    private String attributeCheck(PropertyMetaModel property, String attributeSetterName) {
+        return f("if (node == %s) {" +
+                "    %s((%s) replacementNode);" +
+                "    return true;\n" +
+                "}", property.getName(), attributeSetterName, property.getTypeName());
+    }
+
+    private String nodeListCheck(PropertyMetaModel property) {
+        return f("for (int i = 0; i < %s.size(); i++) {" +
+                "  if (%s.get(i) == node) {" +
+                "    %s.set(i, (%s) replacementNode);" +
+                "    return true;" +
+                "  }" +
+                "}", property.getName(), property.getName(), property.getName(), property.getTypeName());
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/TypeCastingGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/TypeCastingGenerator.java
new file mode 100644
index 0000000..3a611f4
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/node/TypeCastingGenerator.java
@@ -0,0 +1,97 @@
+package com.github.javaparser.generator.core.node;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.generator.NodeGenerator;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import com.github.javaparser.utils.Pair;
+import com.github.javaparser.utils.SourceRoot;
+
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Consumer;
+
+import static com.github.javaparser.JavaParser.parseBodyDeclaration;
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+import static com.github.javaparser.utils.Utils.set;
+
+public class TypeCastingGenerator extends NodeGenerator {
+    private final Set<BaseNodeMetaModel> baseNodes = set(
+            JavaParserMetaModel.statementMetaModel,
+            JavaParserMetaModel.expressionMetaModel,
+            JavaParserMetaModel.typeMetaModel,
+            JavaParserMetaModel.moduleStmtMetaModel,
+            JavaParserMetaModel.bodyDeclarationMetaModel,
+            JavaParserMetaModel.commentMetaModel
+    );
+
+    public TypeCastingGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot);
+    }
+
+    @Override
+    protected void generateNode(BaseNodeMetaModel nodeMetaModel, CompilationUnit nodeCu, ClassOrInterfaceDeclaration nodeCoid) throws Exception {
+        Pair<CompilationUnit, ClassOrInterfaceDeclaration> baseCode = null;
+        for (BaseNodeMetaModel baseNode : baseNodes) {
+            if(nodeMetaModel == baseNode) {
+                // We adjust the base models from the child nodes,
+                // so we don't do anything when we *are* the base model.
+                return;
+            }
+            if (nodeMetaModel.isInstanceOfMetaModel(baseNode)) {
+                baseCode = parseNode(baseNode);
+            }
+        }
+
+        if (baseCode == null) {
+            // Node is not a child of one of the base nodes, so we don't want to generate this method for it.
+            return;
+        }
+
+        final String typeName = nodeMetaModel.getTypeName();
+        final ClassOrInterfaceDeclaration baseCoid = baseCode.b;
+        final CompilationUnit baseCu = baseCode.a;
+        
+        generateIsType(baseCu, nodeCoid, baseCoid, typeName);
+        generateAsType(baseCu, nodeCoid, baseCoid, typeName);
+        generateToType(nodeCu, baseCu, nodeCoid, baseCoid, typeName);
+        generateIfType(nodeCu, baseCu, nodeCoid, baseCoid, typeName);
+    }
+
+    private void generateAsType(CompilationUnit baseCu, ClassOrInterfaceDeclaration nodeCoid, ClassOrInterfaceDeclaration baseCoid, String typeName) {
+        final MethodDeclaration asTypeBaseMethod = (MethodDeclaration) parseBodyDeclaration(f("public %s as%s() { throw new IllegalStateException(f(\"%%s is not an %s\", this)); }", typeName, typeName, typeName));
+        final MethodDeclaration asTypeNodeMethod = (MethodDeclaration) parseBodyDeclaration(f("@Override public %s as%s() { return this; }", typeName, typeName));
+        addOrReplaceWhenSameSignature(baseCoid, asTypeBaseMethod);
+        addOrReplaceWhenSameSignature(nodeCoid, asTypeNodeMethod);
+        baseCu.addImport("com.github.javaparser.utils.CodeGenerationUtils.f", true, false);
+    }
+
+    private void generateToType(CompilationUnit nodeCu, CompilationUnit baseCu, ClassOrInterfaceDeclaration nodeCoid, ClassOrInterfaceDeclaration baseCoid, String typeName) {
+        baseCu.addImport(Optional.class);
+        nodeCu.addImport(Optional.class);
+        final MethodDeclaration asTypeBaseMethod = (MethodDeclaration) parseBodyDeclaration(f("public Optional<%s> to%s() { return Optional.empty(); }", typeName, typeName, typeName));
+        final MethodDeclaration asTypeNodeMethod = (MethodDeclaration) parseBodyDeclaration(f("@Override public Optional<%s> to%s() { return Optional.of(this); }", typeName, typeName));
+        addOrReplaceWhenSameSignature(baseCoid, asTypeBaseMethod);
+        addOrReplaceWhenSameSignature(nodeCoid, asTypeNodeMethod);
+    }
+
+    private void generateIfType(CompilationUnit nodeCu, CompilationUnit baseCu, ClassOrInterfaceDeclaration nodeCoid, ClassOrInterfaceDeclaration baseCoid, String typeName) {
+        final MethodDeclaration ifTypeBaseMethod = (MethodDeclaration) parseBodyDeclaration(f("public void if%s(Consumer<%s> action) { }", typeName, typeName));
+        final MethodDeclaration ifTypeNodeMethod = (MethodDeclaration) parseBodyDeclaration(f("public void if%s(Consumer<%s> action) { action.accept(this); }", typeName, typeName));
+        addOrReplaceWhenSameSignature(baseCoid, ifTypeBaseMethod);
+        addOrReplaceWhenSameSignature(nodeCoid, ifTypeNodeMethod);
+
+        baseCu.addImport(Consumer.class);
+        nodeCu.addImport(Consumer.class);
+    }
+
+    private void generateIsType(CompilationUnit baseCu, ClassOrInterfaceDeclaration nodeCoid, ClassOrInterfaceDeclaration baseCoid, String typeName) {
+        final MethodDeclaration baseIsTypeMethod = (MethodDeclaration) parseBodyDeclaration(f("public boolean is%s() { return false; }", typeName));
+        final MethodDeclaration overriddenIsTypeMethod = (MethodDeclaration) parseBodyDeclaration(f("@Override public boolean is%s() { return true; }", typeName));
+
+        addOrReplaceWhenSameSignature(nodeCoid, overriddenIsTypeMethod);
+        addOrReplaceWhenSameSignature(baseCoid, baseIsTypeMethod);
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/other/GrammarLetterGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/other/GrammarLetterGenerator.java
new file mode 100644
index 0000000..9d50bc6
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/other/GrammarLetterGenerator.java
@@ -0,0 +1,53 @@
+package com.github.javaparser.generator.core.other;
+
+import java.util.function.Function;
+
+/**
+ * Prints the LETTER and PART_LETTER tokens. They should be inserted into the grammar manually.
+ */
+public class GrammarLetterGenerator {
+    public static void main(String[] args) {
+        generate("LETTER", c -> Character.isJavaIdentifierStart(c) || Character.isHighSurrogate((char) (int) c) || Character.isLowSurrogate((char) (int) c));
+        generate("PART_LETTER", c -> Character.isJavaIdentifierPart(c) || Character.isHighSurrogate((char) (int) c) || Character.isLowSurrogate((char) (int) c));
+    }
+
+    private static void generate(String tokenName, Function<Integer, Boolean> f) {
+        final String indent = "         ";
+        System.out.println("  < #" + tokenName + ": [");
+        System.out.print(indent);
+        int nltime = 0;
+        int i = 0;
+        while (i < 0x10000) {
+            while (!f.apply(i) && i < 0x10000) {
+                i++;
+            }
+            String start = format(i);
+            while (f.apply(i) && i < 0x10000) {
+                i++;
+            }
+            String end = format(i - 1);
+            if (i >= 0x10000) {
+                break;
+            }
+            if (start.equals(end)) {
+                nltime++;
+                System.out.print(start + ",  ");
+            } else {
+                nltime += 2;
+                System.out.print(start + "-" + end + ",  ");
+            }
+            if (nltime >= 10) {
+                nltime = 0;
+                System.out.println();
+                System.out.print(indent);
+            }
+        }
+        // Too lazy to remove the final illegal comma.
+        System.out.println("]");
+        System.out.println("  >");
+    }
+
+    private static String format(int i) {
+        return String.format("\"\\u%04x\"", i);
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/other/TokenKindGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/other/TokenKindGenerator.java
new file mode 100644
index 0000000..5088bc3
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/other/TokenKindGenerator.java
@@ -0,0 +1,71 @@
+package com.github.javaparser.generator.core.other;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.body.BodyDeclaration;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.EnumConstantDeclaration;
+import com.github.javaparser.ast.body.EnumDeclaration;
+import com.github.javaparser.ast.expr.IntegerLiteralExpr;
+import com.github.javaparser.ast.stmt.ReturnStmt;
+import com.github.javaparser.ast.stmt.SwitchEntryStmt;
+import com.github.javaparser.ast.stmt.SwitchStmt;
+import com.github.javaparser.generator.Generator;
+import com.github.javaparser.utils.Log;
+import com.github.javaparser.utils.SourceRoot;
+
+/**
+ * Generates the TokenKind enum from {@link com.github.javaparser.GeneratedJavaParserConstants}
+ */
+public class TokenKindGenerator extends Generator {
+    private final SourceRoot generatedJavaCcSourceRoot;
+
+    public TokenKindGenerator(SourceRoot sourceRoot, SourceRoot generatedJavaCcSourceRoot) {
+        super(sourceRoot);
+        this.generatedJavaCcSourceRoot = generatedJavaCcSourceRoot;
+    }
+
+    @Override
+    public void generate() {
+        Log.info("Running %s", getClass().getSimpleName());
+        
+        final CompilationUnit javaTokenCu = sourceRoot.parse("com.github.javaparser", "JavaToken.java");
+        final ClassOrInterfaceDeclaration javaToken = javaTokenCu.getClassByName("JavaToken").orElseThrow(() -> new AssertionError("Can't find class in java file."));
+        final EnumDeclaration kindEnum = javaToken.findFirst(EnumDeclaration.class, e -> e.getNameAsString().equals("Kind")).orElseThrow(() -> new AssertionError("Can't find class in java file."));
+
+        kindEnum.getEntries().clear();
+        annotateGenerated(kindEnum);
+
+        final SwitchStmt valueOfSwitch = kindEnum.findFirst(SwitchStmt.class).orElseThrow(() -> new AssertionError("Can't find valueOf switch."));
+        valueOfSwitch.findAll(SwitchEntryStmt.class).stream().filter(e -> e.getLabel().isPresent()).forEach(Node::remove);
+
+        final CompilationUnit constantsCu = generatedJavaCcSourceRoot.parse("com.github.javaparser", "GeneratedJavaParserConstants.java");
+        final ClassOrInterfaceDeclaration constants = constantsCu.getInterfaceByName("GeneratedJavaParserConstants").orElseThrow(() -> new AssertionError("Can't find class in java file."));
+        for (BodyDeclaration<?> member : constants.getMembers()) {
+            member.toFieldDeclaration()
+                    .filter(field -> {
+                        String javadoc = field.getJavadocComment().get().getContent();
+                        return javadoc.contains("RegularExpression Id") || javadoc.contains("End of File");
+                    })
+                    .map(field -> field.getVariable(0))
+                    .ifPresent(var -> {
+                        final String name = var.getNameAsString();
+                        final IntegerLiteralExpr kind = var.getInitializer().get().asIntegerLiteralExpr();
+                        generateEnumEntry(kindEnum, name, kind);
+                        generateValueOfEntry(valueOfSwitch, name, kind);
+                    });
+        }
+    }
+
+    private void generateValueOfEntry(SwitchStmt valueOfSwitch, String name, IntegerLiteralExpr kind) {
+        final SwitchEntryStmt entry = new SwitchEntryStmt(kind, new NodeList<>(new ReturnStmt(name)));
+        valueOfSwitch.getEntries().addFirst(entry);
+    }
+
+    private void generateEnumEntry(EnumDeclaration kindEnum, String name, IntegerLiteralExpr kind) {
+        final EnumConstantDeclaration enumEntry = new EnumConstantDeclaration(name);
+        enumEntry.getArguments().add(kind);
+        kindEnum.addEntry(enumEntry);
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/CloneVisitorGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/CloneVisitorGenerator.java
new file mode 100644
index 0000000..44a7e9f
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/CloneVisitorGenerator.java
@@ -0,0 +1,59 @@
+package com.github.javaparser.generator.core.visitor;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.generator.VisitorGenerator;
+import com.github.javaparser.utils.SeparatedItemStringBuilder;
+import com.github.javaparser.utils.SourceRoot;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.PropertyMetaModel;
+
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+
+/**
+ * Generates JavaParser's CloneVisitor.
+ */
+public class CloneVisitorGenerator extends VisitorGenerator {
+    public CloneVisitorGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot, "com.github.javaparser.ast.visitor", "CloneVisitor", "Visitable", "Object", true);
+    }
+
+    @Override
+    protected void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod, CompilationUnit compilationUnit) {
+        visitMethod.getParameters().forEach(p -> p.setFinal(true));
+
+        BlockStmt body = visitMethod.getBody().get();
+        body.getStatements().clear();
+
+        for (PropertyMetaModel field : node.getAllPropertyMetaModels()) {
+            final String getter = field.getGetterMethodName() + "()";
+            if (field.getNodeReference().isPresent()) {
+                if (field.isOptional() && field.isNodeList()) {
+                    body.addStatement(f("NodeList<%s> %s = cloneList(n.%s.orElse(null), arg);", field.getTypeNameGenerified(), field.getName(), getter));
+                } else if (field.isNodeList()) {
+                    body.addStatement(f("NodeList<%s> %s = cloneList(n.%s, arg);", field.getTypeNameGenerified(), field.getName(), getter));
+                } else {
+                    body.addStatement(f("%s %s = cloneNode(n.%s, arg);", field.getTypeNameGenerified(), field.getName(), getter));
+                }
+            }
+        }
+
+        SeparatedItemStringBuilder builder = new SeparatedItemStringBuilder(f("%s r = new %s(", node.getTypeNameGenerified(), node.getTypeNameGenerified()), ",", ");");
+        builder.append("n.getTokenRange().orElse(null)");
+        for (PropertyMetaModel field : node.getConstructorParameters()) {
+            if (field.getName().equals("comment")) {
+                continue;
+            }
+            if (field.getNodeReference().isPresent()) {
+                builder.append(field.getName());
+            } else {
+                builder.append(f("n.%s()", field.getGetterMethodName()));
+            }
+        }
+
+        body.addStatement(builder.toString());
+        body.addStatement("r.setComment(comment);");
+        body.addStatement("return r;");
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/EqualsVisitorGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/EqualsVisitorGenerator.java
new file mode 100644
index 0000000..7517f8e
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/EqualsVisitorGenerator.java
@@ -0,0 +1,48 @@
+package com.github.javaparser.generator.core.visitor;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.generator.VisitorGenerator;
+import com.github.javaparser.utils.SourceRoot;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.PropertyMetaModel;
+
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+
+/**
+ * Generates JavaParser's EqualsVisitor.
+ */
+public class EqualsVisitorGenerator extends VisitorGenerator {
+    public EqualsVisitorGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot, "com.github.javaparser.ast.visitor", "EqualsVisitor", "Boolean", "Visitable", true);
+    }
+
+    @Override
+    protected void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod, CompilationUnit compilationUnit) {
+        visitMethod.getParameters().forEach(p -> p.setFinal(true));
+
+        BlockStmt body = visitMethod.getBody().get();
+        body.getStatements().clear();
+
+        body.addStatement(f("final %s n2 = (%s) arg;", node.getTypeName(), node.getTypeName()));
+
+        for (PropertyMetaModel field : node.getAllPropertyMetaModels()) {
+            final String getter = field.getGetterMethodName() + "()";
+            if (field.getNodeReference().isPresent()) {
+                if (field.isNodeList()) {
+                    body.addStatement(f("if (!nodesEquals(n.%s, n2.%s)) return false;", getter, getter));
+                } else {
+                    body.addStatement(f("if (!nodeEquals(n.%s, n2.%s)) return false;", getter, getter));
+                }
+            } else {
+                body.addStatement(f("if (!objEquals(n.%s, n2.%s)) return false;", getter, getter));
+            }
+        }
+        if (body.getStatements().size() == 1) {
+            // Only the cast line was added, but nothing is using it, so remove it again.
+            body.getStatements().clear();
+        }
+        body.addStatement("return true;");
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/GenericListVisitorAdapterGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/GenericListVisitorAdapterGenerator.java
new file mode 100644
index 0000000..f910108
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/GenericListVisitorAdapterGenerator.java
@@ -0,0 +1,56 @@
+package com.github.javaparser.generator.core.visitor;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.generator.VisitorGenerator;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.PropertyMetaModel;
+import com.github.javaparser.utils.SourceRoot;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+
+/**
+ * Generates JavaParser's GenericListVisitorAdapter.
+ */
+public class GenericListVisitorAdapterGenerator extends VisitorGenerator {
+    public GenericListVisitorAdapterGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot, "com.github.javaparser.ast.visitor", "GenericListVisitorAdapter", "List<R>", "A", true);
+    }
+
+    @Override
+    protected void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod, CompilationUnit compilationUnit) {
+        visitMethod.getParameters().forEach(p -> p.setFinal(true));
+
+        BlockStmt body = visitMethod.getBody().get();
+        body.getStatements().clear();
+        body.addStatement("List<R> result = new ArrayList<>();");
+        body.addStatement("List<R> tmp;");
+
+        final String resultCheck = "if (tmp != null) result.addAll(tmp);";
+
+        for (PropertyMetaModel field : node.getAllPropertyMetaModels()) {
+            final String getter = field.getGetterMethodName() + "()";
+            if (field.getNodeReference().isPresent()) {
+                if (field.isOptional()) {
+                    body.addStatement(f("if (n.%s.isPresent()) {" +
+                            "   tmp = n.%s.get().accept(this, arg);" +
+                            "   %s" +
+                            "}", getter, getter, resultCheck));
+                } else {
+                    body.addStatement(f("{ tmp = n.%s.accept(this, arg); %s }", getter, resultCheck));
+                }
+            }
+        }
+        body.addStatement("return result;");
+        Arrays.stream(new Class<?>[] {List.class, ArrayList.class}).filter(c ->
+                compilationUnit.getImports().stream().noneMatch(
+                        i -> c.getName().equals(i.getName().asString())
+                )
+        ).forEach(compilationUnit::addImport);
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/GenericVisitorAdapterGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/GenericVisitorAdapterGenerator.java
new file mode 100644
index 0000000..72f563d
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/GenericVisitorAdapterGenerator.java
@@ -0,0 +1,47 @@
+package com.github.javaparser.generator.core.visitor;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.generator.VisitorGenerator;
+import com.github.javaparser.utils.SourceRoot;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.PropertyMetaModel;
+
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+
+/**
+ * Generates JavaParser's VoidVisitorAdapter.
+ */
+public class GenericVisitorAdapterGenerator extends VisitorGenerator {
+    public GenericVisitorAdapterGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot, "com.github.javaparser.ast.visitor", "GenericVisitorAdapter", "R", "A", true);
+    }
+
+    @Override
+    protected void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod, CompilationUnit compilationUnit) {
+        visitMethod.getParameters().forEach(p -> p.setFinal(true));
+
+        BlockStmt body = visitMethod.getBody().get();
+        body.getStatements().clear();
+        
+        body.addStatement("R result;");
+
+        final String resultCheck = "if (result != null) return result;";
+
+        for (PropertyMetaModel field : node.getAllPropertyMetaModels()) {
+            final String getter = field.getGetterMethodName() + "()";
+            if (field.getNodeReference().isPresent()) {
+                if (field.isOptional()) {
+                    body.addStatement(f("if (n.%s.isPresent()) {" +
+                            "   result = n.%s.get().accept(this, arg);" +
+                            "   %s" +
+                            "}", getter, getter, resultCheck));
+                } else {
+                    body.addStatement(f("{ result = n.%s.accept(this, arg); %s }", getter, resultCheck));
+                }
+            }
+        }
+        body.addStatement("return null;");
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/GenericVisitorGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/GenericVisitorGenerator.java
new file mode 100644
index 0000000..e71aeb1
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/GenericVisitorGenerator.java
@@ -0,0 +1,23 @@
+package com.github.javaparser.generator.core.visitor;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.generator.VisitorGenerator;
+import com.github.javaparser.utils.SourceRoot;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+
+/**
+ * Generates JavaParser's GenericVisitor.
+ */
+public class GenericVisitorGenerator extends VisitorGenerator {
+    public GenericVisitorGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot, "com.github.javaparser.ast.visitor", "GenericVisitor", "R", "A", true);
+    }
+
+    @Override
+    protected void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod, CompilationUnit compilationUnit) {
+        visitMethod.getParameters().forEach(p -> p.setFinal(false));
+        
+        visitMethod.setBody(null);
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/GenericVisitorWithDefaultsGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/GenericVisitorWithDefaultsGenerator.java
new file mode 100644
index 0000000..a6a2151
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/GenericVisitorWithDefaultsGenerator.java
@@ -0,0 +1,27 @@
+package com.github.javaparser.generator.core.visitor;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.generator.VisitorGenerator;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.utils.SourceRoot;
+
+/**
+ * Generates JavaParser's GenericVisitorWithDefaults.
+ */
+public class GenericVisitorWithDefaultsGenerator extends VisitorGenerator {
+    public GenericVisitorWithDefaultsGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot, "com.github.javaparser.ast.visitor", "GenericVisitorWithDefaults", "R", "A", true);
+    }
+
+    @Override
+    protected void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod, CompilationUnit compilationUnit) {
+        visitMethod.getParameters().forEach(p -> p.setFinal(true));
+
+        BlockStmt body = visitMethod.getBody().get();
+        body.getStatements().clear();
+
+        body.addStatement("return defaultAction(n, arg);");
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/HashCodeVisitorGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/HashCodeVisitorGenerator.java
new file mode 100644
index 0000000..554dc8d
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/HashCodeVisitorGenerator.java
@@ -0,0 +1,59 @@
+package com.github.javaparser.generator.core.visitor;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.generator.VisitorGenerator;
+import com.github.javaparser.utils.SeparatedItemStringBuilder;
+import com.github.javaparser.utils.SourceRoot;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.PropertyMetaModel;
+
+import java.util.List;
+
+import static com.github.javaparser.JavaParser.parseStatement;
+
+/**
+ * Generates JavaParser's HashCodeVisitor.
+ */
+public class HashCodeVisitorGenerator extends VisitorGenerator {
+    public HashCodeVisitorGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot, "com.github.javaparser.ast.visitor", "HashCodeVisitor", "Integer", "Void", true);
+    }
+
+    @Override
+    protected void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod, CompilationUnit compilationUnit) {
+        visitMethod.getParameters().forEach(p -> p.setFinal(true));
+
+        final BlockStmt body = visitMethod.getBody().get();
+        body.getStatements().clear();
+
+        final SeparatedItemStringBuilder builder = new SeparatedItemStringBuilder("return ", "* 31 +", ";");
+        final List<PropertyMetaModel> propertyMetaModels= node.getAllPropertyMetaModels();
+        if (propertyMetaModels.isEmpty()) {
+            builder.append("0");
+        } else {
+            for (PropertyMetaModel field : propertyMetaModels) {
+                final String getter = field.getGetterMethodName() + "()";
+                // Is this field another AST node? Visit it.
+                if (field.getNodeReference().isPresent()) {
+                    if (field.isOptional()) {
+                        builder.append("(n.%s.isPresent()? n.%s.get().accept(this, arg):0)", getter, getter);
+                    } else {
+                        builder.append("(n.%s.accept(this, arg))", getter);
+                    }
+                } else {
+                    Class<?> type = field.getType();
+                    if (type.equals(boolean.class)) {
+                        builder.append("(n.%s?1:0)", getter);
+                    } else if (type.equals(int.class)) {
+                        builder.append("n.%s", getter);
+                    } else {
+                        builder.append("(n.%s.hashCode())", getter);
+                    }
+                }
+            }
+        }
+        body.addStatement(parseStatement(builder.toString()));
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/ModifierVisitorGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/ModifierVisitorGenerator.java
new file mode 100644
index 0000000..4c2f711
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/ModifierVisitorGenerator.java
@@ -0,0 +1,78 @@
+package com.github.javaparser.generator.core.visitor;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.expr.BinaryExpr;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.generator.VisitorGenerator;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.PropertyMetaModel;
+import com.github.javaparser.utils.SeparatedItemStringBuilder;
+import com.github.javaparser.utils.SourceRoot;
+
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+
+public class ModifierVisitorGenerator extends VisitorGenerator {
+    public ModifierVisitorGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot, "com.github.javaparser.ast.visitor", "ModifierVisitor", "Visitable", "A", true);
+    }
+
+    @Override
+    protected void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod, CompilationUnit compilationUnit) {
+        visitMethod.getParameters().forEach(p -> p.setFinal(true));
+
+        BlockStmt body = visitMethod.getBody().get();
+        body.getStatements().clear();
+
+        for (PropertyMetaModel property : node.getAllPropertyMetaModels()) {
+            if (property.isNode()) {
+                if (property.isNodeList()) {
+                    body.addStatement(f("NodeList<%s> %s = modifyList(n.%s(), arg);",
+                            property.getTypeNameGenerified(),
+                            property.getName(),
+                            property.getGetterMethodName()));
+                } else if (property.isOptional()) {
+                    body.addStatement(f("%s %s = n.%s().map(s -> (%s) s.accept(this, arg)).orElse(null);",
+                            property.getTypeNameGenerified(),
+                            property.getName(),
+                            property.getGetterMethodName(),
+                            property.getTypeNameGenerified()));
+                } else {
+                    body.addStatement(f("%s %s = (%s) n.%s().accept(this, arg);",
+                            property.getTypeNameGenerified(),
+                            property.getName(),
+                            property.getTypeNameGenerified(),
+                            property.getGetterMethodName()));
+                }
+            }
+        }
+
+        if(node.is(BinaryExpr.class)){
+            body.addStatement("if (left == null) return right;");
+            body.addStatement("if (right == null) return left;");
+        }else {
+            final SeparatedItemStringBuilder collapseCheck = new SeparatedItemStringBuilder("if(", "||", ") return null;");
+            for (PropertyMetaModel property : node.getAllPropertyMetaModels()) {
+                if (property.isRequired() && property.isNode()) {
+                    if (property.isNodeList()) {
+                        if(property.isNonEmpty()){
+                            collapseCheck.append(f("%s.isEmpty()", property.getName()));
+                        }
+                    } else {
+                        collapseCheck.append(f("%s==null", property.getName()));
+                    }
+                }
+            }
+            if (collapseCheck.hasItems()) {
+                body.addStatement(collapseCheck.toString());
+            }
+        }
+
+        for (PropertyMetaModel property : node.getAllPropertyMetaModels()) {
+            if (property.isNode()) {
+                body.addStatement(f("n.%s(%s);", property.getSetterMethodName(), property.getName()));
+            }
+        }
+        body.addStatement("return n;");
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/NoCommentEqualsVisitorGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/NoCommentEqualsVisitorGenerator.java
new file mode 100644
index 0000000..f6174c4
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/NoCommentEqualsVisitorGenerator.java
@@ -0,0 +1,76 @@
+/*

+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.

+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.

+ *

+ * This file is part of JavaParser.

+ *

+ * JavaParser can be used either under the terms of

+ * a) the GNU Lesser General Public License as published by

+ *     the Free Software Foundation, either version 3 of the License, or

+ *     (at your option) any later version.

+ * b) the terms of the Apache License

+ *

+ * You should have received a copy of both licenses in LICENCE.LGPL and

+ * LICENCE.APACHE. Please refer to those files for details.

+ *

+ * JavaParser is distributed in the hope that it will be useful,

+ * but WITHOUT ANY WARRANTY; without even the implied warranty of

+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ * GNU Lesser General Public License for more details.

+ */

+

+package com.github.javaparser.generator.core.visitor;

+

+import static com.github.javaparser.utils.CodeGenerationUtils.f;

+

+import com.github.javaparser.ast.CompilationUnit;

+import com.github.javaparser.ast.body.MethodDeclaration;

+import com.github.javaparser.ast.stmt.BlockStmt;

+import com.github.javaparser.generator.VisitorGenerator;

+import com.github.javaparser.metamodel.BaseNodeMetaModel;

+import com.github.javaparser.metamodel.JavaParserMetaModel;

+import com.github.javaparser.metamodel.PropertyMetaModel;

+import com.github.javaparser.utils.SourceRoot;

+

+public class NoCommentEqualsVisitorGenerator extends VisitorGenerator {

+

+    public NoCommentEqualsVisitorGenerator(SourceRoot sourceRoot) {

+        super(sourceRoot, "com.github.javaparser.ast.visitor", "NoCommentEqualsVisitor", "Boolean", "Visitable", true);

+    }

+

+    @Override

+    protected void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod,

+                                           CompilationUnit compilationUnit) {

+        visitMethod.getParameters().forEach(p -> p.setFinal(true));

+

+        BlockStmt body = visitMethod.getBody().get();

+        body.getStatements().clear();

+

+        if (!(node.equals(JavaParserMetaModel.lineCommentMetaModel)

+                || node.equals(JavaParserMetaModel.blockCommentMetaModel)

+                || node.equals(JavaParserMetaModel.javadocCommentMetaModel))) {

+

+            body.addStatement(f("final %s n2 = (%s) arg;", node.getTypeName(), node.getTypeName()));

+

+            for (PropertyMetaModel field : node.getAllPropertyMetaModels()) {

+                final String getter = field.getGetterMethodName() + "()";

+                if (field.equals(JavaParserMetaModel.nodeMetaModel.commentPropertyMetaModel))

+                    continue;

+                if (field.getNodeReference().isPresent()) {

+                    if (field.isNodeList()) {

+                        body.addStatement(f("if (!nodesEquals(n.%s, n2.%s)) return false;", getter, getter));

+                    } else {

+                        body.addStatement(f("if (!nodeEquals(n.%s, n2.%s)) return false;", getter, getter));

+                    }

+                } else {

+                    body.addStatement(f("if (!objEquals(n.%s, n2.%s)) return false;", getter, getter));

+                }

+            }

+            if (body.getStatements().size() == 1) {

+                // Only the cast line was added, but nothing is using it, so remove it again.

+                body.getStatements().clear();

+            }

+        }

+        body.addStatement("return true;");

+    }

+}
\ No newline at end of file
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/NoCommentHashCodeVisitorGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/NoCommentHashCodeVisitorGenerator.java
new file mode 100644
index 0000000..b36d259
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/NoCommentHashCodeVisitorGenerator.java
@@ -0,0 +1,89 @@
+/*

+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.

+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.

+ *

+ * This file is part of JavaParser.

+ *

+ * JavaParser can be used either under the terms of

+ * a) the GNU Lesser General Public License as published by

+ *     the Free Software Foundation, either version 3 of the License, or

+ *     (at your option) any later version.

+ * b) the terms of the Apache License

+ *

+ * You should have received a copy of both licenses in LICENCE.LGPL and

+ * LICENCE.APACHE. Please refer to those files for details.

+ *

+ * JavaParser is distributed in the hope that it will be useful,

+ * but WITHOUT ANY WARRANTY; without even the implied warranty of

+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ * GNU Lesser General Public License for more details.

+ */

+

+package com.github.javaparser.generator.core.visitor;

+

+import static com.github.javaparser.JavaParser.parseStatement;

+

+import java.util.List;

+

+import com.github.javaparser.ast.CompilationUnit;

+import com.github.javaparser.ast.body.MethodDeclaration;

+import com.github.javaparser.ast.stmt.BlockStmt;

+import com.github.javaparser.generator.VisitorGenerator;

+import com.github.javaparser.metamodel.BaseNodeMetaModel;

+import com.github.javaparser.metamodel.JavaParserMetaModel;

+import com.github.javaparser.metamodel.PropertyMetaModel;

+import com.github.javaparser.utils.SeparatedItemStringBuilder;

+import com.github.javaparser.utils.SourceRoot;

+

+public class NoCommentHashCodeVisitorGenerator extends VisitorGenerator {

+

+    public NoCommentHashCodeVisitorGenerator(SourceRoot sourceRoot) {

+        super(sourceRoot, "com.github.javaparser.ast.visitor", "NoCommentHashCodeVisitor", "Integer", "Void", true);

+    }

+

+    @Override

+    protected void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod,

+                                           CompilationUnit compilationUnit) {

+        visitMethod.getParameters().forEach(p -> p.setFinal(true));

+

+        final BlockStmt body = visitMethod.getBody().get();

+        body.getStatements().clear();

+

+        final SeparatedItemStringBuilder builder = new SeparatedItemStringBuilder("return ", "* 31 +", ";");

+        final List<PropertyMetaModel> propertyMetaModels = node.getAllPropertyMetaModels();

+        if (node.equals(JavaParserMetaModel.lineCommentMetaModel)

+                || node.equals(JavaParserMetaModel.blockCommentMetaModel)

+                || node.equals(JavaParserMetaModel.javadocCommentMetaModel) || propertyMetaModels.isEmpty()) {

+            builder.append("0");

+        } else {

+            for (PropertyMetaModel field : propertyMetaModels) {

+                final String getter = field.getGetterMethodName() + "()";

+                if (field.equals(JavaParserMetaModel.nodeMetaModel.commentPropertyMetaModel)) {

+                    if (propertyMetaModels.size() == 1) {

+                        builder.append("0");

+                        break;

+                    } else

+                        continue;

+                }

+                // Is this field another AST node? Visit it.

+                if (field.getNodeReference().isPresent()) {

+                    if (field.isOptional()) {

+                        builder.append("(n.%s.isPresent()? n.%s.get().accept(this, arg):0)", getter, getter);

+                    } else {

+                        builder.append("(n.%s.accept(this, arg))", getter);

+                    }

+                } else {

+                    Class<?> type = field.getType();

+                    if (type.equals(boolean.class)) {

+                        builder.append("(n.%s?1:0)", getter);

+                    } else if (type.equals(int.class)) {

+                        builder.append("n.%s", getter);

+                    } else {

+                        builder.append("(n.%s.hashCode())", getter);

+                    }

+                }

+            }

+        }

+        body.addStatement(parseStatement(builder.toString()));

+    }

+}

diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/ObjectIdentityEqualsVisitorGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/ObjectIdentityEqualsVisitorGenerator.java
new file mode 100644
index 0000000..3c182fc
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/ObjectIdentityEqualsVisitorGenerator.java
@@ -0,0 +1,30 @@
+package com.github.javaparser.generator.core.visitor;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.generator.VisitorGenerator;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.PropertyMetaModel;
+import com.github.javaparser.utils.SourceRoot;
+
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+
+/**
+ * Generates JavaParser's ObjectIdentityEqualsVisitor.
+ */
+public class ObjectIdentityEqualsVisitorGenerator extends VisitorGenerator {
+    public ObjectIdentityEqualsVisitorGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot, "com.github.javaparser.ast.visitor", "ObjectIdentityEqualsVisitor", "Boolean", "Visitable", true);
+    }
+
+    @Override
+    protected void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod, CompilationUnit compilationUnit) {
+        visitMethod.getParameters().forEach(p -> p.setFinal(true));
+
+        BlockStmt body = visitMethod.getBody().get();
+        body.getStatements().clear();
+
+        body.addStatement("return n == arg;");
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/ObjectIdentityHashCodeVisitorGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/ObjectIdentityHashCodeVisitorGenerator.java
new file mode 100644
index 0000000..88eb3e7
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/ObjectIdentityHashCodeVisitorGenerator.java
@@ -0,0 +1,32 @@
+package com.github.javaparser.generator.core.visitor;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.generator.VisitorGenerator;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.PropertyMetaModel;
+import com.github.javaparser.utils.SeparatedItemStringBuilder;
+import com.github.javaparser.utils.SourceRoot;
+
+import java.util.List;
+
+import static com.github.javaparser.JavaParser.parseStatement;
+
+/**
+ * Generates JavaParser's ObjectIdentityHashCodeVisitor.
+ */
+public class ObjectIdentityHashCodeVisitorGenerator extends VisitorGenerator {
+    public ObjectIdentityHashCodeVisitorGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot, "com.github.javaparser.ast.visitor", "ObjectIdentityHashCodeVisitor", "Integer", "Void", true);
+    }
+
+    @Override
+    protected void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod, CompilationUnit compilationUnit) {
+        visitMethod.getParameters().forEach(p -> p.setFinal(true));
+
+        final BlockStmt body = visitMethod.getBody().get();
+        body.getStatements().clear();
+        body.addStatement("return n.hashCode();");
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/VoidVisitorAdapterGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/VoidVisitorAdapterGenerator.java
new file mode 100644
index 0000000..937ea7e
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/VoidVisitorAdapterGenerator.java
@@ -0,0 +1,43 @@
+package com.github.javaparser.generator.core.visitor;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.generator.VisitorGenerator;
+import com.github.javaparser.utils.SourceRoot;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.PropertyMetaModel;
+
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+
+/**
+ * Generates JavaParser's VoidVisitorAdapter.
+ */
+public class VoidVisitorAdapterGenerator extends VisitorGenerator {
+    public VoidVisitorAdapterGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot, "com.github.javaparser.ast.visitor", "VoidVisitorAdapter", "void", "A", true);
+    }
+
+    @Override
+    protected void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod, CompilationUnit compilationUnit) {
+        visitMethod.getParameters().forEach(p -> p.setFinal(true));
+
+        BlockStmt body = visitMethod.getBody().get();
+        body.getStatements().clear();
+
+        for (PropertyMetaModel field : node.getAllPropertyMetaModels()) {
+            final String getter = field.getGetterMethodName() + "()";
+            if (field.getNodeReference().isPresent()) {
+                if (field.isOptional() && field.isNodeList()) {
+                    body.addStatement(f("n.%s.ifPresent( l -> l.forEach( v -> v.accept(this, arg)));", getter));
+                } else if (field.isOptional()) {
+                    body.addStatement(f("n.%s.ifPresent(l -> l.accept(this, arg));", getter));
+                } else if (field.isNodeList()) {
+                    body.addStatement(f("n.%s.forEach(p -> p.accept(this, arg));", getter));
+                } else {
+                    body.addStatement(f("n.%s.accept(this, arg);", getter));
+                }
+            }
+        }
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/VoidVisitorGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/VoidVisitorGenerator.java
new file mode 100644
index 0000000..e3326d3
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/VoidVisitorGenerator.java
@@ -0,0 +1,23 @@
+package com.github.javaparser.generator.core.visitor;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.generator.VisitorGenerator;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.utils.SourceRoot;
+
+/**
+ * Generates JavaParser's VoidVisitor.
+ */
+public class VoidVisitorGenerator extends VisitorGenerator {
+    public VoidVisitorGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot, "com.github.javaparser.ast.visitor", "VoidVisitor", "void", "A", true);
+    }
+
+    @Override
+    protected void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod, CompilationUnit compilationUnit) {
+        visitMethod.getParameters().forEach(p -> p.setFinal(false));
+
+        visitMethod.setBody(null);
+    }
+}
diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/VoidVisitorWithDefaultsGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/VoidVisitorWithDefaultsGenerator.java
new file mode 100644
index 0000000..4089061
--- /dev/null
+++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/VoidVisitorWithDefaultsGenerator.java
@@ -0,0 +1,27 @@
+package com.github.javaparser.generator.core.visitor;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.generator.VisitorGenerator;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.utils.SourceRoot;
+
+/**
+ * Generates JavaParser's VoidVisitorWithDefaults.
+ */
+public class VoidVisitorWithDefaultsGenerator extends VisitorGenerator {
+    public VoidVisitorWithDefaultsGenerator(SourceRoot sourceRoot) {
+        super(sourceRoot, "com.github.javaparser.ast.visitor", "VoidVisitorWithDefaults", "void", "A", true);
+    }
+
+    @Override
+    protected void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod, CompilationUnit compilationUnit) {
+        visitMethod.getParameters().forEach(p -> p.setFinal(true));
+
+        BlockStmt body = visitMethod.getBody().get();
+        body.getStatements().clear();
+
+        body.addStatement("defaultAction(n, arg);");
+    }
+}
diff --git a/javaparser-core/bnd.bnd b/javaparser-core/bnd.bnd
new file mode 100644
index 0000000..9f43eea
--- /dev/null
+++ b/javaparser-core/bnd.bnd
@@ -0,0 +1,33 @@
+# Make the Bundle-SymbolicName fully qualified, not just the artifact id
+Bundle-SymbolicName: com.github.javaparser.javaparser-core
+
+# Export all packages except impl
+-exportcontents: \
+    com.github.javaparser, \
+    com.github.javaparser.javadoc, \
+    com.github.javaparser.javadoc.description, \
+    com.github.javaparser.metamodel, \
+    com.github.javaparser.printer, \
+    com.github.javaparser.printer.concretesyntaxmodel, \
+    com.github.javaparser.resolution, \
+    com.github.javaparser.resolution.declarations, \
+    com.github.javaparser.resolution.types, \
+    com.github.javaparser.resolution.types.parametrization, \
+    com.github.javaparser.utils, \
+    com.github.javaparser.ast, \
+    com.github.javaparser.ast.body, \
+    com.github.javaparser.ast.imports, \
+    com.github.javaparser.ast.comments, \
+    com.github.javaparser.ast.modules, \
+    com.github.javaparser.ast.nodeTypes, \
+    com.github.javaparser.ast.nodeTypes.modifiers, \
+    com.github.javaparser.ast.expr, \
+    com.github.javaparser.ast.stmt, \
+    com.github.javaparser.ast.type, \
+    com.github.javaparser.ast.visitor, \
+    com.github.javaparser.ast.validator, \
+    com.github.javaparser.ast.observer
+
+# Don't use the project's version for the packages
+# We prefer not setting a version as we don't follow OSGi version semantics
+-nodefaultversion: true
diff --git a/javaparser-core/javaparser-core.iml b/javaparser-core/javaparser-core.iml
new file mode 100644
index 0000000..055eff4
--- /dev/null
+++ b/javaparser-core/javaparser-core.iml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
+    <output url="file://$MODULE_DIR$/target/classes" />
+    <output-test url="file://$MODULE_DIR$/target/test-classes" />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/javacc-support" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/target/generated-sources/java-templates" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/target/generated-sources/javacc" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/target/generated-sources/license" isTestSource="false" generated="true" />
+      <excludeFolder url="file://$MODULE_DIR$/target" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/javaparser-core/pom.xml b/javaparser-core/pom.xml
new file mode 100644
index 0000000..356b13d
--- /dev/null
+++ b/javaparser-core/pom.xml
@@ -0,0 +1,173 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>javaparser-parent</artifactId>
+        <groupId>com.github.javaparser</groupId>
+        <version>3.5.16-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>javaparser-core</artifactId>
+    <packaging>jar</packaging>
+    <description>The core parser functionality. This may be all you need.</description>
+
+    <licenses>
+        <license>
+            <name>GNU Lesser General Public License</name>
+            <url>http://www.gnu.org/licenses/lgpl-3.0.html</url>
+            <distribution>repo</distribution>
+        </license>
+        <license>
+            <name>Apache License, Version 2.0</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <distribution>repo</distribution>
+            <comments>A business-friendly OSS license</comments>
+        </license>
+    </licenses>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <build.timestamp>${maven.build.timestamp}</build.timestamp>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>com.helger.maven</groupId>
+                <artifactId>ph-javacc-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>javacc</id>
+                        <goals>
+                            <goal>javacc</goal>
+                        </goals>
+                        <configuration>
+                            <grammarEncoding>${project.build.sourceEncoding}</grammarEncoding>
+                            <jdkVersion>${java.version}</jdkVersion>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>animal-sniffer-maven-plugin</artifactId>
+                <configuration>
+                    <signature>
+                        <!-- Make sure only the API of this JDK is used -->
+                        <groupId>org.codehaus.mojo.signature</groupId>
+                        <artifactId>java18</artifactId>
+                        <version>1.0</version>
+                    </signature>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>animal-sniffer</id>
+                        <phase>verify</phase>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-enforcer-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>enforce-versions</id>
+                        <phase>verify</phase>
+                        <goals>
+                            <goal>enforce</goal>
+                        </goals>
+                        <configuration>
+                            <rules>
+                                <requireJavaVersion>
+                                    <!-- Make sure a compiler of this version is used -->
+                                    <version>${java.version}</version>
+                                </requireJavaVersion>
+                                <enforceBytecodeVersion>
+                                    <!-- Make sure the dependencies are compiled for our Java version -->
+                                    <maxJdkVersion>${java.version}</maxJdkVersion>
+                                </enforceBytecodeVersion>
+                            </rules>
+                        </configuration>
+                    </execution>
+                </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>extra-enforcer-rules</artifactId>
+                        <version>1.0-beta-6</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+            <!-- Generate an OSGi-enabled MANIFEST during the build -->
+            <plugin>
+                <groupId>biz.aQute.bnd</groupId>
+                <artifactId>bnd-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>bnd-process</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <!-- Make sure the bnd-generated manifest is picked up, see MJAR-193 -->
+                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+                        <!-- Set module name -->
+                        <manifestEntries>
+                            <Automatic-Module-Name>com.github.javaparser.core</Automatic-Module-Name>
+                        </manifestEntries>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <compilerArgs>
+                        <!-- This stores method parameter names in the class file, which are used by the metamodel generator -->
+                        <arg>-parameters</arg>
+                    </compilerArgs>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>add-source</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>src/main/javacc-support</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>templating-maven-plugin</artifactId>
+                <version>1.0.0</version>
+                <executions>
+                    <execution>
+                        <id>filter-src</id>
+                        <goals>
+                            <goal>filter-sources</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/javaparser-core/src/main/java-templates/com/github/javaparser/JavaParserBuild.java b/javaparser-core/src/main/java-templates/com/github/javaparser/JavaParserBuild.java
new file mode 100644
index 0000000..2e0ee9c
--- /dev/null
+++ b/javaparser-core/src/main/java-templates/com/github/javaparser/JavaParserBuild.java
@@ -0,0 +1,19 @@
+package com.github.javaparser;
+
+/**
+ * Some information that was available when this library was built by Maven.
+ */
+public class JavaParserBuild {
+    public static final String PROJECT_VERSION = "${project.version}";
+    public static final String PROJECT_NAME = "${project.name}";
+    public static final String PROJECT_BUILD_FINAL_NAME = "${project.build.finalName}";
+    public static final String MAVEN_VERSION = "${maven.version}";
+    public static final String MAVEN_BUILD_VERSION = "${maven.build.version}";
+    public static final String MAVEN_BUILD_TIMESTAMP = "${build.timestamp}";
+    public static final String JAVA_VENDOR ="${java.vendor}";
+    public static final String JAVA_VENDOR_URL ="${java.vendor.url}";
+    public static final String JAVA_VERSION ="${java.version}";
+    public static final String OS_ARCH ="${os.arch}";
+    public static final String OS_NAME ="${os.name}";
+    public static final String OS_VERSION ="${os.version}";
+}
\ No newline at end of file
diff --git a/javaparser-core/src/main/java/com/github/javaparser/CommentsInserter.java b/javaparser-core/src/main/java/com/github/javaparser/CommentsInserter.java
new file mode 100644
index 0000000..869883c
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/CommentsInserter.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.comments.Comment;
+import com.github.javaparser.ast.comments.LineComment;
+import com.github.javaparser.utils.PositionUtils;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import static com.github.javaparser.ast.Node.NODE_BY_BEGIN_POSITION;
+
+/**
+ * Assigns comments to nodes of the AST.
+ *
+ * @author Sebastian Kuerten
+ * @author Júlio Vilmar Gesser
+ */
+class CommentsInserter {
+    private final ParserConfiguration configuration;
+
+    CommentsInserter(ParserConfiguration configuration) {
+        this.configuration = configuration;
+    }
+
+    /**
+     * Comments are attributed to the thing they comment and are removed from
+     * the comments.
+     */
+    private void insertComments(CompilationUnit cu, TreeSet<Comment> comments) {
+        if (comments.isEmpty())
+            return;
+
+        /* I should sort all the direct children and the comments, if a comment
+         is the first thing then it
+         a comment to the CompilationUnit */
+
+        // FIXME if there is no package it could be also a comment to the following class...
+        // so I could use some heuristics in these cases to distinguish the two
+        // cases
+
+        List<Node> children = cu.getChildNodes();
+
+        Comment firstComment = comments.iterator().next();
+        if (cu.getPackageDeclaration().isPresent()
+                && (children.isEmpty() || PositionUtils.areInOrder(
+                firstComment, cu.getPackageDeclaration().get()))) {
+            cu.setComment(firstComment);
+            comments.remove(firstComment);
+        }
+    }
+
+    /**
+     * This method try to attributes the nodes received to child of the node. It
+     * returns the node that were not attributed.
+     */
+    void insertComments(Node node, TreeSet<Comment> commentsToAttribute) {
+        if (commentsToAttribute.isEmpty())
+            return;
+
+        if (node instanceof CompilationUnit) {
+            insertComments((CompilationUnit) node, commentsToAttribute);
+        }
+
+        // the comments can:
+        // 1) Inside one of the child, then it is the child that have to
+        // associate them
+        // 2) If they are not inside a child they could be preceeding nothing, a
+        // comment or a child
+        // if they preceed a child they are assigned to it, otherweise they
+        // remain "orphans"
+
+        List<Node> children = node.getChildNodes();
+
+        for (Node child : children) {
+            TreeSet<Comment> commentsInsideChild = new TreeSet<>(NODE_BY_BEGIN_POSITION);
+            commentsInsideChild.addAll(
+                    commentsToAttribute.stream()
+                            .filter(c -> c.getRange().isPresent())
+                            .filter(c -> PositionUtils.nodeContains(child, c,
+                                    configuration.isDoNotConsiderAnnotationsAsNodeStartForCodeAttribution())).collect(Collectors.toList()));
+            commentsToAttribute.removeAll(commentsInsideChild);
+            insertComments(child, commentsInsideChild);
+        }
+
+        attributeLineCommentsOnSameLine(commentsToAttribute, children);
+
+        /* at this point I create an ordered list of all remaining comments and
+         children */
+        Comment previousComment = null;
+        final List<Comment> attributedComments = new LinkedList<>();
+        List<Node> childrenAndComments = new LinkedList<>();
+        // Avoid attributing comments to a meaningless container.
+        childrenAndComments.addAll(children);
+        commentsToAttribute.removeAll(attributedComments);
+
+        childrenAndComments.addAll(commentsToAttribute);
+        PositionUtils.sortByBeginPosition(childrenAndComments,
+                configuration.isDoNotConsiderAnnotationsAsNodeStartForCodeAttribution());
+
+        for (Node thing : childrenAndComments) {
+            if (thing instanceof Comment) {
+                previousComment = (Comment) thing;
+                if (!previousComment.isOrphan()) {
+                    previousComment = null;
+                }
+            } else {
+                if (previousComment != null && !thing.getComment().isPresent()) {
+                    if (!configuration.isDoNotAssignCommentsPrecedingEmptyLines()
+                            || !thereAreLinesBetween(previousComment, thing)) {
+                        thing.setComment(previousComment);
+                        attributedComments.add(previousComment);
+                        previousComment = null;
+                    }
+                }
+            }
+        }
+
+        commentsToAttribute.removeAll(attributedComments);
+
+        // all the remaining are orphan nodes
+        for (Comment c : commentsToAttribute) {
+            if (c.isOrphan()) {
+                node.addOrphanComment(c);
+            }
+        }
+    }
+
+    private void attributeLineCommentsOnSameLine(TreeSet<Comment> commentsToAttribute, List<Node> children) {
+        /* I can attribute in line comments to elements preceeding them, if
+         there is something contained in their line */
+        List<Comment> attributedComments = new LinkedList<>();
+        commentsToAttribute.stream()
+                .filter(comment -> comment.getRange().isPresent())
+                .filter(Comment::isLineComment)
+                .forEach(comment -> children.stream()
+                        .filter(child -> child.getRange().isPresent())
+                        .forEach(child -> {
+                            Range commentRange = comment.getRange().get();
+                            Range childRange = child.getRange().get();
+                            if (childRange.end.line == commentRange.begin.line
+                                    && attributeLineCommentToNodeOrChild(child,
+                                    comment.asLineComment())) {
+                                attributedComments.add(comment);
+                            }
+                        }));
+        commentsToAttribute.removeAll(attributedComments);
+    }
+
+    private boolean attributeLineCommentToNodeOrChild(Node node, LineComment lineComment) {
+        if (!node.getRange().isPresent() || !lineComment.getRange().isPresent()) {
+            return false;
+        }
+        
+        // The node start and end at the same line as the comment,
+        // let's give to it the comment
+        if (node.getBegin().get().line == lineComment.getBegin().get().line
+                && !node.getComment().isPresent()) {
+            if (!(node instanceof Comment)) {
+                node.setComment(lineComment);
+            }
+            return true;
+        } else {
+            // try with all the children, sorted by reverse position (so the
+            // first one is the nearest to the comment
+            List<Node> children = new LinkedList<>();
+            children.addAll(node.getChildNodes());
+            PositionUtils.sortByBeginPosition(children);
+            Collections.reverse(children);
+
+            for (Node child : children) {
+                if (attributeLineCommentToNodeOrChild(child, lineComment)) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+    }
+
+    private boolean thereAreLinesBetween(Node a, Node b) {
+        if (!a.getRange().isPresent() || !b.getRange().isPresent()) {
+            return true;
+        }
+        if (!PositionUtils.areInOrder(a, b)) {
+            return thereAreLinesBetween(b, a);
+        }
+        int endOfA = a.getEnd().get().line;
+        return b.getBegin().get().line > endOfA + 1;
+    }
+
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/HasParentNode.java b/javaparser-core/src/main/java/com/github/javaparser/HasParentNode.java
new file mode 100644
index 0000000..03df0d6
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/HasParentNode.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser;
+
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.observer.Observable;
+
+import java.util.Optional;
+
+/**
+ * An object that has a parent node.
+ */
+public interface HasParentNode<T> extends Observable {
+
+    /**
+     * Return the parent node or null, if no parent is set.
+     */
+    Optional<Node> getParentNode();
+
+    /**
+     * Set the parent node.
+     *
+     * @param parentNode the parent node or null, to set no parent
+     * @return return <i>this</i>
+     */
+    T setParentNode(Node parentNode);
+
+    /**
+     * <i>this</i> for everything except NodeLists. NodeLists use their parent as their children parent.
+     */
+    Node getParentNodeForChildren();
+
+    /**
+     * Get the ancestor of the node having the given type, or null if no ancestor of the given type is found.
+     */
+    default <N> Optional<N> getAncestorOfType(Class<N> classType) {
+        Node parent = getParentNode().orElse(null);
+        while (parent != null) {
+            if (classType.isAssignableFrom(parent.getClass())) {
+                return Optional.of(classType.cast(parent));
+            }
+            parent = parent.getParentNode().orElse(null);
+        }
+        return Optional.empty();
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/JavaParser.java b/javaparser-core/src/main/java/com/github/javaparser/JavaParser.java
new file mode 100644
index 0000000..7b8ee87
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/JavaParser.java
@@ -0,0 +1,522 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.ImportDeclaration;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.PackageDeclaration;
+import com.github.javaparser.ast.body.BodyDeclaration;
+import com.github.javaparser.ast.body.Parameter;
+import com.github.javaparser.ast.expr.*;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt;
+import com.github.javaparser.ast.stmt.Statement;
+import com.github.javaparser.ast.type.ClassOrInterfaceType;
+import com.github.javaparser.ast.type.Type;
+import com.github.javaparser.javadoc.Javadoc;
+
+import java.io.*;
+import java.nio.charset.Charset;
+import java.nio.file.Path;
+
+import static com.github.javaparser.ParseStart.*;
+import static com.github.javaparser.Problem.PROBLEM_BY_BEGIN_POSITION;
+import static com.github.javaparser.Providers.*;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+
+/**
+ * Parse Java source code and creates Abstract Syntax Trees.
+ *
+ * @author Júlio Vilmar Gesser
+ */
+public final class JavaParser {
+    private final ParserConfiguration configuration;
+
+    private GeneratedJavaParser astParser = null;
+    private static ParserConfiguration staticConfiguration = new ParserConfiguration();
+
+    /**
+     * Instantiate the parser with default configuration. Note that parsing can also be done with the static methods on
+     * this class.
+     * Creating an instance will reduce setup time between parsing files.
+     */
+    public JavaParser() {
+        this(new ParserConfiguration());
+    }
+
+    /**
+     * Instantiate the parser. Note that parsing can also be done with the static methods on this class.
+     * Creating an instance will reduce setup time between parsing files.
+     */
+    public JavaParser(ParserConfiguration configuration) {
+        this.configuration = configuration;
+    }
+
+    /**
+     * Get the configuration for the static parse... methods.
+     * This is a STATIC field, so modifying it will directly change how all static parse... methods work!
+     */
+    public static ParserConfiguration getStaticConfiguration() {
+        return staticConfiguration;
+    }
+
+    /**
+     * Set the configuration for the static parse... methods.
+     * This is a STATIC field, so modifying it will directly change how all static parse... methods work!
+     */
+    public static void setStaticConfiguration(ParserConfiguration staticConfiguration) {
+        JavaParser.staticConfiguration = staticConfiguration;
+    }
+
+    /**
+     * Get the non-static configuration for this parser.
+     *
+     * @return The non-static configuration for this parser.
+     */
+    public ParserConfiguration getParserConfiguration() {
+        return this.configuration;
+    }
+
+    private GeneratedJavaParser getParserForProvider(Provider provider) {
+        if (astParser == null) {
+            astParser = new GeneratedJavaParser(provider);
+        } else {
+            astParser.reset(provider);
+        }
+        astParser.setTabSize(configuration.getTabSize());
+        astParser.setStoreTokens(configuration.isStoreTokens());
+        return astParser;
+    }
+
+    /**
+     * Parses source code.
+     * It takes the source code from a Provider.
+     * The start indicates what can be found in the source code (compilation unit, block, import...)
+     *
+     * @param start refer to the constants in ParseStart to see what can be parsed.
+     * @param provider refer to Providers to see how you can read source. The provider will be closed after parsing.
+     * @param <N> the subclass of Node that is the result of parsing in the start.
+     * @return the parse result, a collection of encountered problems, and some extra data.
+     */
+    public <N extends Node> ParseResult<N> parse(ParseStart<N> start, Provider provider) {
+        assertNotNull(start);
+        assertNotNull(provider);
+        final GeneratedJavaParser parser = getParserForProvider(provider);
+        try {
+            N resultNode = start.parse(parser);
+            ParseResult<N> result = new ParseResult<>(resultNode, parser.problems, parser.getTokens(),
+                    parser.getCommentsCollection());
+
+            configuration.getPostProcessors().forEach(postProcessor ->
+                    postProcessor.process(result, configuration));
+
+            result.getProblems().sort(PROBLEM_BY_BEGIN_POSITION);
+
+            return result;
+        } catch (Exception e) {
+            final String message = e.getMessage() == null ? "Unknown error" : e.getMessage();
+            parser.problems.add(new Problem(message, null, e));
+            return new ParseResult<>(null, parser.problems, parser.getTokens(), parser.getCommentsCollection());
+        } finally {
+            try {
+                provider.close();
+            } catch (IOException e) {
+                // Since we're done parsing and have our result, we don't care about any errors.
+            }
+        }
+    }
+
+    /**
+     * Parses the Java code contained in the {@link InputStream} and returns a
+     * {@link CompilationUnit} that represents it.
+     *
+     * @param in {@link InputStream} containing Java source code. It will be closed after parsing.
+     * @param encoding encoding of the source code
+     * @return CompilationUnit representing the Java source code
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static CompilationUnit parse(final InputStream in, Charset encoding) {
+        return simplifiedParse(COMPILATION_UNIT, provider(in, encoding));
+    }
+
+    /**
+     * Parses the Java code contained in the {@link InputStream} and returns a
+     * {@link CompilationUnit} that represents it.<br>
+     * Note: Uses UTF-8 encoding
+     *
+     * @param in {@link InputStream} containing Java source code. It will be closed after parsing.
+     * @return CompilationUnit representing the Java source code
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static CompilationUnit parse(final InputStream in) {
+        return parse(in, UTF8);
+    }
+
+    /**
+     * Parses the Java code contained in a {@link File} and returns a
+     * {@link CompilationUnit} that represents it.
+     *
+     * @param file {@link File} containing Java source code. It will be closed after parsing.
+     * @param encoding encoding of the source code
+     * @return CompilationUnit representing the Java source code
+     * @throws ParseProblemException if the source code has parser errors
+     * @throws FileNotFoundException the file was not found
+     */
+    public static CompilationUnit parse(final File file, final Charset encoding) throws FileNotFoundException {
+        return simplifiedParse(COMPILATION_UNIT, provider(file, encoding)).setStorage(file.toPath());
+    }
+
+    /**
+     * Parses the Java code contained in a {@link File} and returns a
+     * {@link CompilationUnit} that represents it.<br>
+     * Note: Uses UTF-8 encoding
+     *
+     * @param file {@link File} containing Java source code. It will be closed after parsing.
+     * @return CompilationUnit representing the Java source code
+     * @throws ParseProblemException if the source code has parser errors
+     * @throws FileNotFoundException the file was not found
+     */
+    public static CompilationUnit parse(final File file) throws FileNotFoundException {
+        return simplifiedParse(COMPILATION_UNIT, provider(file)).setStorage(file.toPath());
+    }
+
+    /**
+     * Parses the Java code contained in a file and returns a
+     * {@link CompilationUnit} that represents it.
+     *
+     * @param path path to a file containing Java source code
+     * @param encoding encoding of the source code
+     * @return CompilationUnit representing the Java source code
+     * @throws IOException the path could not be accessed
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static CompilationUnit parse(final Path path, final Charset encoding) throws IOException {
+        return simplifiedParse(COMPILATION_UNIT, provider(path, encoding)).setStorage(path);
+    }
+
+    /**
+     * Parses the Java code contained in a file and returns a
+     * {@link CompilationUnit} that represents it.<br>
+     * Note: Uses UTF-8 encoding
+     *
+     * @param path path to a file containing Java source code
+     * @return CompilationUnit representing the Java source code
+     * @throws ParseProblemException if the source code has parser errors
+     * @throws IOException the path could not be accessed
+     */
+    public static CompilationUnit parse(final Path path) throws IOException {
+        return simplifiedParse(COMPILATION_UNIT, provider(path)).setStorage(path);
+    }
+
+    /**
+     * Parses the Java code contained in a resource and returns a
+     * {@link CompilationUnit} that represents it.<br>
+     * Note: Uses UTF-8 encoding
+     *
+     * @param path path to a resource containing Java source code. As resource is accessed through a class loader, a
+     * leading "/" is not allowed in pathToResource
+     * @return CompilationUnit representing the Java source code
+     * @throws ParseProblemException if the source code has parser errors
+     * @throws IOException the path could not be accessed
+     */
+    public static CompilationUnit parseResource(final String path) throws IOException {
+        return simplifiedParse(COMPILATION_UNIT, resourceProvider(path));
+    }
+
+    /**
+     * Parses the Java code contained in a resource and returns a
+     * {@link CompilationUnit} that represents it.<br>
+     *
+     * @param path path to a resource containing Java source code. As resource is accessed through a class loader, a
+     * leading "/" is not allowed in pathToResource
+     * @param encoding encoding of the source code
+     * @return CompilationUnit representing the Java source code
+     * @throws ParseProblemException if the source code has parser errors
+     * @throws IOException the path could not be accessed
+     */
+    public static CompilationUnit parseResource(final String path, Charset encoding) throws IOException {
+        return simplifiedParse(COMPILATION_UNIT, resourceProvider(path, encoding));
+    }
+
+    /**
+     * Parses the Java code contained in a resource and returns a
+     * {@link CompilationUnit} that represents it.<br>
+     *
+     * @param classLoader the classLoader that is asked to load the resource
+     * @param path path to a resource containing Java source code. As resource is accessed through a class loader, a
+     * leading "/" is not allowed in pathToResource
+     * @return CompilationUnit representing the Java source code
+     * @throws ParseProblemException if the source code has parser errors
+     * @throws IOException the path could not be accessed
+     */
+    public static CompilationUnit parseResource(final ClassLoader classLoader, final String path, Charset encoding) throws IOException {
+        return simplifiedParse(COMPILATION_UNIT, resourceProvider(classLoader, path, encoding));
+    }
+
+    /**
+     * Parses Java code from a Reader and returns a
+     * {@link CompilationUnit} that represents it.<br>
+     *
+     * @param reader the reader containing Java source code. It will be closed after parsing.
+     * @return CompilationUnit representing the Java source code
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static CompilationUnit parse(final Reader reader) {
+        return simplifiedParse(COMPILATION_UNIT, provider(reader));
+    }
+
+    /**
+     * Parses the Java code contained in code and returns a
+     * {@link CompilationUnit} that represents it.
+     *
+     * @param code Java source code
+     * @return CompilationUnit representing the Java source code
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static CompilationUnit parse(String code) {
+        return simplifiedParse(COMPILATION_UNIT, provider(code));
+    }
+
+    /**
+     * Parses the Java block contained in a {@link String} and returns a
+     * {@link BlockStmt} that represents it.
+     *
+     * @param blockStatement {@link String} containing Java block code
+     * @return BlockStmt representing the Java block
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static BlockStmt parseBlock(final String blockStatement) {
+        return simplifiedParse(BLOCK, provider(blockStatement));
+    }
+
+    /**
+     * Parses the Java statement contained in a {@link String} and returns a
+     * {@link Statement} that represents it.
+     *
+     * @param statement {@link String} containing Java statement code
+     * @return Statement representing the Java statement
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static Statement parseStatement(final String statement) {
+        return simplifiedParse(STATEMENT, provider(statement));
+    }
+
+    private static <T extends Node> T simplifiedParse(ParseStart<T> context, Provider provider) {
+        ParseResult<T> result = new JavaParser(staticConfiguration).parse(context, provider);
+        if (result.isSuccessful()) {
+            return result.getResult().get();
+        }
+        throw new ParseProblemException(result.getProblems());
+    }
+
+    /**
+     * Parses the Java import contained in a {@link String} and returns a
+     * {@link ImportDeclaration} that represents it.
+     *
+     * @param importDeclaration {@link String} containing Java import code
+     * @return ImportDeclaration representing the Java import declaration
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static ImportDeclaration parseImport(final String importDeclaration) {
+        return simplifiedParse(IMPORT_DECLARATION, provider(importDeclaration));
+    }
+
+    /**
+     * Parses the Java expression contained in a {@link String} and returns a
+     * {@link Expression} that represents it.
+     *
+     * @param expression {@link String} containing Java expression
+     * @return Expression representing the Java expression
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Expression> T parseExpression(final String expression) {
+        return (T) simplifiedParse(EXPRESSION, provider(expression));
+    }
+
+    /**
+     * Parses the Java annotation contained in a {@link String} and returns a
+     * {@link AnnotationExpr} that represents it.
+     *
+     * @param annotation {@link String} containing Java annotation
+     * @return AnnotationExpr representing the Java annotation
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static AnnotationExpr parseAnnotation(final String annotation) {
+        return simplifiedParse(ANNOTATION, provider(annotation));
+    }
+
+    /**
+     * Parses the Java annotation body declaration(e.g fields or methods) contained in a
+     * {@link String} and returns a {@link BodyDeclaration} that represents it.
+     *
+     * @param body {@link String} containing Java body declaration
+     * @return BodyDeclaration representing the Java annotation
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static BodyDeclaration<?> parseAnnotationBodyDeclaration(final String body) {
+        return simplifiedParse(ANNOTATION_BODY, provider(body));
+    }
+
+    /**
+     * Parses a Java class body declaration(e.g fields or methods) and returns a
+     * {@link BodyDeclaration} that represents it.
+     *
+     * @param body the body of a class
+     * @return BodyDeclaration representing the Java class body
+     * @throws ParseProblemException if the source code has parser errors
+     * @deprecated just use parseBodyDeclaration now.
+     */
+    @Deprecated
+    public static BodyDeclaration<?> parseClassBodyDeclaration(String body) {
+        return parseBodyDeclaration(body);
+    }
+
+    /**
+     * Parses a Java interface body declaration(e.g fields or methods) and returns a
+     * {@link BodyDeclaration} that represents it.
+     *
+     * @param body the body of an interface
+     * @return BodyDeclaration representing the Java interface body
+     * @throws ParseProblemException if the source code has parser errors
+     * @deprecated just use parseBodyDeclaration now.
+     */
+    @Deprecated
+    public static BodyDeclaration<?> parseInterfaceBodyDeclaration(String body) {
+        return parseBodyDeclaration(body);
+    }
+
+    /**
+     * Parses a Java class or interface body declaration(e.g fields or methods) and returns a
+     * {@link BodyDeclaration} that represents it.
+     *
+     * @param body the body of a class or interface
+     * @return BodyDeclaration representing the Java interface body
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static BodyDeclaration<?> parseBodyDeclaration(String body) {
+        return simplifiedParse(CLASS_BODY, provider(body));
+    }
+
+    /**
+     * Parses a Java class or interface type name and returns a {@link ClassOrInterfaceType} that represents it.
+     *
+     * @param type the type name like a.b.c.X or Y
+     * @return ClassOrInterfaceType representing the type
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static ClassOrInterfaceType parseClassOrInterfaceType(String type) {
+        return simplifiedParse(CLASS_OR_INTERFACE_TYPE, provider(type));
+    }
+
+    /**
+     * Parses a Java type name and returns a {@link Type} that represents it.
+     *
+     * @param type the type name like a.b.c.X, Y, or int
+     * @return ClassOrInterfaceType representing the type
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static Type parseType(String type) {
+        return simplifiedParse(TYPE, provider(type));
+    }
+
+    /**
+     * Parses a variable declaration expression and returns a {@link com.github.javaparser.ast.expr.VariableDeclarationExpr}
+     * that represents it.
+     *
+     * @param declaration a variable declaration like <code>int x=2;</code>
+     * @return VariableDeclarationExpr representing the type
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static VariableDeclarationExpr parseVariableDeclarationExpr(String declaration) {
+        return simplifiedParse(VARIABLE_DECLARATION_EXPR, provider(declaration));
+    }
+
+    /**
+     * Parses the content of a JavadocComment and returns a {@link com.github.javaparser.javadoc.Javadoc} that
+     * represents it.
+     *
+     * @param content a variable declaration like <code>content of my javadoc\n * second line\n * third line</code>
+     * @return Javadoc representing the content of the comment
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static Javadoc parseJavadoc(String content) {
+        return JavadocParser.parse(content);
+    }
+
+    /**
+     * Parses the this(...) and super(...) statements that may occur at the start of a constructor.
+     *
+     * @param statement a statement like super("hello");
+     * @return the AST for the statement.
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static ExplicitConstructorInvocationStmt parseExplicitConstructorInvocationStmt(String statement) {
+        return simplifiedParse(EXPLICIT_CONSTRUCTOR_INVOCATION_STMT, provider(statement));
+    }
+
+    /**
+     * Parses a qualified name (one that can have "."s in it) and returns it as a Name.
+     *
+     * @param qualifiedName a name like "com.laamella.parameter_source"
+     * @return the AST for the name
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static Name parseName(String qualifiedName) {
+        return simplifiedParse(NAME, provider(qualifiedName));
+    }
+
+    /**
+     * Parses a simple name (one that can NOT have "."s in it) and returns it as a SimpleName.
+     *
+     * @param name a name like "parameter_source"
+     * @return the AST for the name
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static SimpleName parseSimpleName(String name) {
+        return simplifiedParse(SIMPLE_NAME, provider(name));
+    }
+
+    /**
+     * Parses a single parameter (a type and a name) and returns it as a Parameter.
+     *
+     * @param parameter a parameter like "int[] x"
+     * @return the AST for the parameter
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static Parameter parseParameter(String parameter) {
+        return simplifiedParse(PARAMETER, provider(parameter));
+    }
+
+
+    /**
+     * Parses a package declaration and returns it as a PackageDeclaration.
+     *
+     * @param packageDeclaration a declaration like "package com.microsoft.java;"
+     * @return the AST for the parameter
+     * @throws ParseProblemException if the source code has parser errors
+     */
+    public static PackageDeclaration parsePackageDeclaration(String packageDeclaration) {
+        return simplifiedParse(PACKAGE_DECLARATION, provider(packageDeclaration));
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/JavaToken.java b/javaparser-core/src/main/java/com/github/javaparser/JavaToken.java
new file mode 100644
index 0000000..ad56ff5
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/JavaToken.java
@@ -0,0 +1,796 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser;
+
+import java.util.List;
+import java.util.Optional;
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+import static com.github.javaparser.utils.Utils.EOL;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+import javax.annotation.Generated;
+
+/**
+ * A token from a parsed source file.
+ * (Awkwardly named "Java"Token since JavaCC already generates an internal class Token.)
+ * It is a node in a double linked list called token list.
+ */
+public class JavaToken {
+
+    public static final JavaToken INVALID = new JavaToken();
+
+    private Range range;
+
+    private int kind;
+
+    private String text;
+
+    private JavaToken previousToken = null;
+
+    private JavaToken nextToken = null;
+
+    private JavaToken() {
+        this(null, 0, "INVALID", null, null);
+    }
+
+    public JavaToken(int kind, String text) {
+        this(null, kind, text, null, null);
+    }
+
+    JavaToken(Token token, List<JavaToken> tokens) {
+        // You could be puzzled by the following lines
+        // 
+        // The reason why these lines are necessary is the fact that Java is ambiguous. There are cases where the
+        // sequence of characters ">>>" and ">>" should be recognized as the single tokens ">>>" and ">>". In other
+        // cases however we want to split those characters in single GT tokens (">").
+        // 
+        // For example, in expressions ">>" and ">>>" are valid, while when defining types we could have this:
+        // 
+        // List<List<Set<String>>>>
+        // 
+        // You can see that the sequence ">>>>" should be interpreted as four consecutive ">" tokens closing a type
+        // parameter list.
+        // 
+        // The JavaCC handle this case by first recognizing always the longest token, and then depending on the context
+        // putting back the unused chars in the stream. However in those cases the token provided is invalid: it has an
+        // image corresponding to the text originally recognized, without considering that after some characters could
+        // have been put back into the stream.
+        // 
+        // So in the case of:
+        // 
+        // List<List<Set<String>>>>
+        // ___   -> recognized as ">>>", then ">>" put back in the stream but Token(type=GT, image=">>>") passed to this class
+        // ___  -> recognized as ">>>", then ">>" put back in the stream but Token(type=GT, image=">>>") passed to this class
+        // __  -> recognized as ">>", then ">" put back in the stream but Token(type=GT, image=">>") passed to this class
+        // _  -> Token(type=GT, image=">") good!
+        // 
+        // So given the image could be wrong but the type is correct, we look at the type of the token and we fix
+        // the image. Everybody is happy and we can keep this horrible thing as our little secret.
+        Range range = Range.range(token.beginLine, token.beginColumn, token.endLine, token.endColumn);
+        String text = token.image;
+        if (token.kind == GeneratedJavaParserConstants.GT) {
+            range = Range.range(token.beginLine, token.beginColumn, token.endLine, token.beginColumn);
+            text = ">";
+        } else if (token.kind == GeneratedJavaParserConstants.RSIGNEDSHIFT) {
+            range = Range.range(token.beginLine, token.beginColumn, token.endLine, token.beginColumn + 1);
+            text = ">>";
+        }
+        this.range = range;
+        this.kind = token.kind;
+        this.text = text;
+        if (!tokens.isEmpty()) {
+            final JavaToken previousToken = tokens.get(tokens.size() - 1);
+            this.previousToken = previousToken;
+            previousToken.nextToken = this;
+        } else {
+            previousToken = null;
+        }
+    }
+
+    /**
+     * Create a token of a certain kind.
+     */
+    public JavaToken(int kind) {
+        String content = GeneratedJavaParserConstants.tokenImage[kind];
+        if (content.startsWith("\"")) {
+            content = content.substring(1, content.length() - 1);
+        }
+        if (TokenTypes.isEndOfLineToken(kind)) {
+            content = EOL;
+        } else if (TokenTypes.isWhitespace(kind)) {
+            content = " ";
+        }
+        this.kind = kind;
+        this.text = content;
+    }
+
+    public JavaToken(Range range, int kind, String text, JavaToken previousToken, JavaToken nextToken) {
+        assertNotNull(text);
+        this.range = range;
+        this.kind = kind;
+        this.text = text;
+        this.previousToken = previousToken;
+        this.nextToken = nextToken;
+    }
+
+    public Optional<Range> getRange() {
+        return Optional.ofNullable(range);
+    }
+
+    public int getKind() {
+        return kind;
+    }
+
+    void setKind(int kind) {
+        this.kind = kind;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public Optional<JavaToken> getNextToken() {
+        return Optional.ofNullable(nextToken);
+    }
+
+    public Optional<JavaToken> getPreviousToken() {
+        return Optional.ofNullable(previousToken);
+    }
+
+    public void setRange(Range range) {
+        this.range = range;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+    public String asString() {
+        return text;
+    }
+
+    /**
+     * @return the token range that goes from the beginning to the end of the token list this token is a part of.
+     */
+    public TokenRange toTokenRange() {
+        return new TokenRange(findFirstToken(), findLastToken());
+    }
+
+    @Override
+    public String toString() {
+        String text = getText().replace("\n", "\\n").replace("\r", "\\r").replace("\r\n", "\\r\\n").replace("\t", "\\t");
+        return f("\"%s\"   <%s>   %s", text, getKind(), getRange().map(Range::toString).orElse("(?)-(?)"));
+    }
+
+    /**
+     * Used by the parser while constructing nodes. No tokens should be invalid when the parser is done.
+     */
+    public boolean valid() {
+        return !invalid();
+    }
+
+    /**
+     * Used by the parser while constructing nodes. No tokens should be invalid when the parser is done.
+     */
+    public boolean invalid() {
+        return this == INVALID;
+    }
+
+    public enum Category {
+
+        WHITESPACE_NO_EOL,
+        EOL,
+        COMMENT,
+        IDENTIFIER,
+        KEYWORD,
+        LITERAL,
+        SEPARATOR,
+        OPERATOR;
+
+        public boolean isWhitespaceOrComment() {
+            return isWhitespace() || this == COMMENT;
+        }
+
+        public boolean isWhitespace() {
+            return this == WHITESPACE_NO_EOL || this == EOL;
+        }
+
+        public boolean isEndOfLine() {
+            return this == EOL;
+        }
+
+        public boolean isComment() {
+            return this == COMMENT;
+        }
+
+        public boolean isWhitespaceButNotEndOfLine() {
+            return this == WHITESPACE_NO_EOL;
+        }
+
+        public boolean isIdentifier() {
+            return this == IDENTIFIER;
+        }
+
+        public boolean isKeyword() {
+            return this == KEYWORD;
+        }
+
+        public boolean isLiteral() {
+            return this == LITERAL;
+        }
+
+        public boolean isSeparator() {
+            return this == SEPARATOR;
+        }
+
+        public boolean isOperator() {
+            return this == OPERATOR;
+        }
+    }
+
+    @Generated("com.github.javaparser.generator.core.other.TokenKindGenerator")
+    public enum Kind {
+
+        EOF(0),
+        SPACE(1),
+        WINDOWS_EOL(2),
+        UNIX_EOL(3),
+        OLD_MAC_EOL(4),
+        SINGLE_LINE_COMMENT(5),
+        ENTER_JAVADOC_COMMENT(6),
+        ENTER_MULTILINE_COMMENT(7),
+        JAVADOC_COMMENT(8),
+        MULTI_LINE_COMMENT(9),
+        COMMENT_CONTENT(10),
+        ABSTRACT(11),
+        ASSERT(12),
+        BOOLEAN(13),
+        BREAK(14),
+        BYTE(15),
+        CASE(16),
+        CATCH(17),
+        CHAR(18),
+        CLASS(19),
+        CONST(20),
+        CONTINUE(21),
+        _DEFAULT(22),
+        DO(23),
+        DOUBLE(24),
+        ELSE(25),
+        ENUM(26),
+        EXTENDS(27),
+        FALSE(28),
+        FINAL(29),
+        FINALLY(30),
+        FLOAT(31),
+        FOR(32),
+        GOTO(33),
+        IF(34),
+        IMPLEMENTS(35),
+        IMPORT(36),
+        INSTANCEOF(37),
+        INT(38),
+        INTERFACE(39),
+        LONG(40),
+        NATIVE(41),
+        NEW(42),
+        NULL(43),
+        PACKAGE(44),
+        PRIVATE(45),
+        PROTECTED(46),
+        PUBLIC(47),
+        RETURN(48),
+        SHORT(49),
+        STATIC(50),
+        STRICTFP(51),
+        SUPER(52),
+        SWITCH(53),
+        SYNCHRONIZED(54),
+        THIS(55),
+        THROW(56),
+        THROWS(57),
+        TRANSIENT(58),
+        TRUE(59),
+        TRY(60),
+        VOID(61),
+        VOLATILE(62),
+        WHILE(63),
+        REQUIRES(64),
+        TO(65),
+        WITH(66),
+        OPEN(67),
+        OPENS(68),
+        USES(69),
+        MODULE(70),
+        EXPORTS(71),
+        PROVIDES(72),
+        TRANSITIVE(73),
+        LONG_LITERAL(74),
+        INTEGER_LITERAL(75),
+        DECIMAL_LITERAL(76),
+        HEX_LITERAL(77),
+        OCTAL_LITERAL(78),
+        BINARY_LITERAL(79),
+        FLOATING_POINT_LITERAL(80),
+        DECIMAL_FLOATING_POINT_LITERAL(81),
+        DECIMAL_EXPONENT(82),
+        HEXADECIMAL_FLOATING_POINT_LITERAL(83),
+        HEXADECIMAL_EXPONENT(84),
+        HEX_DIGITS(85),
+        UNICODE_ESCAPE(86),
+        CHARACTER_LITERAL(87),
+        STRING_LITERAL(88),
+        IDENTIFIER(89),
+        LETTER(90),
+        PART_LETTER(91),
+        LPAREN(92),
+        RPAREN(93),
+        LBRACE(94),
+        RBRACE(95),
+        LBRACKET(96),
+        RBRACKET(97),
+        SEMICOLON(98),
+        COMMA(99),
+        DOT(100),
+        AT(101),
+        ASSIGN(102),
+        LT(103),
+        BANG(104),
+        TILDE(105),
+        HOOK(106),
+        COLON(107),
+        EQ(108),
+        LE(109),
+        GE(110),
+        NE(111),
+        SC_OR(112),
+        SC_AND(113),
+        INCR(114),
+        DECR(115),
+        PLUS(116),
+        MINUS(117),
+        STAR(118),
+        SLASH(119),
+        BIT_AND(120),
+        BIT_OR(121),
+        XOR(122),
+        REM(123),
+        LSHIFT(124),
+        PLUSASSIGN(125),
+        MINUSASSIGN(126),
+        STARASSIGN(127),
+        SLASHASSIGN(128),
+        ANDASSIGN(129),
+        ORASSIGN(130),
+        XORASSIGN(131),
+        REMASSIGN(132),
+        LSHIFTASSIGN(133),
+        RSIGNEDSHIFTASSIGN(134),
+        RUNSIGNEDSHIFTASSIGN(135),
+        ELLIPSIS(136),
+        ARROW(137),
+        DOUBLECOLON(138),
+        RUNSIGNEDSHIFT(139),
+        RSIGNEDSHIFT(140),
+        GT(141),
+        CTRL_Z(142);
+
+        private final int kind;
+
+        Kind(int kind) {
+            this.kind = kind;
+        }
+
+        public static Kind valueOf(int kind) {
+            switch(kind) {
+                case 142:
+                    return CTRL_Z;
+                case 141:
+                    return GT;
+                case 140:
+                    return RSIGNEDSHIFT;
+                case 139:
+                    return RUNSIGNEDSHIFT;
+                case 138:
+                    return DOUBLECOLON;
+                case 137:
+                    return ARROW;
+                case 136:
+                    return ELLIPSIS;
+                case 135:
+                    return RUNSIGNEDSHIFTASSIGN;
+                case 134:
+                    return RSIGNEDSHIFTASSIGN;
+                case 133:
+                    return LSHIFTASSIGN;
+                case 132:
+                    return REMASSIGN;
+                case 131:
+                    return XORASSIGN;
+                case 130:
+                    return ORASSIGN;
+                case 129:
+                    return ANDASSIGN;
+                case 128:
+                    return SLASHASSIGN;
+                case 127:
+                    return STARASSIGN;
+                case 126:
+                    return MINUSASSIGN;
+                case 125:
+                    return PLUSASSIGN;
+                case 124:
+                    return LSHIFT;
+                case 123:
+                    return REM;
+                case 122:
+                    return XOR;
+                case 121:
+                    return BIT_OR;
+                case 120:
+                    return BIT_AND;
+                case 119:
+                    return SLASH;
+                case 118:
+                    return STAR;
+                case 117:
+                    return MINUS;
+                case 116:
+                    return PLUS;
+                case 115:
+                    return DECR;
+                case 114:
+                    return INCR;
+                case 113:
+                    return SC_AND;
+                case 112:
+                    return SC_OR;
+                case 111:
+                    return NE;
+                case 110:
+                    return GE;
+                case 109:
+                    return LE;
+                case 108:
+                    return EQ;
+                case 107:
+                    return COLON;
+                case 106:
+                    return HOOK;
+                case 105:
+                    return TILDE;
+                case 104:
+                    return BANG;
+                case 103:
+                    return LT;
+                case 102:
+                    return ASSIGN;
+                case 101:
+                    return AT;
+                case 100:
+                    return DOT;
+                case 99:
+                    return COMMA;
+                case 98:
+                    return SEMICOLON;
+                case 97:
+                    return RBRACKET;
+                case 96:
+                    return LBRACKET;
+                case 95:
+                    return RBRACE;
+                case 94:
+                    return LBRACE;
+                case 93:
+                    return RPAREN;
+                case 92:
+                    return LPAREN;
+                case 91:
+                    return PART_LETTER;
+                case 90:
+                    return LETTER;
+                case 89:
+                    return IDENTIFIER;
+                case 88:
+                    return STRING_LITERAL;
+                case 87:
+                    return CHARACTER_LITERAL;
+                case 86:
+                    return UNICODE_ESCAPE;
+                case 85:
+                    return HEX_DIGITS;
+                case 84:
+                    return HEXADECIMAL_EXPONENT;
+                case 83:
+                    return HEXADECIMAL_FLOATING_POINT_LITERAL;
+                case 82:
+                    return DECIMAL_EXPONENT;
+                case 81:
+                    return DECIMAL_FLOATING_POINT_LITERAL;
+                case 80:
+                    return FLOATING_POINT_LITERAL;
+                case 79:
+                    return BINARY_LITERAL;
+                case 78:
+                    return OCTAL_LITERAL;
+                case 77:
+                    return HEX_LITERAL;
+                case 76:
+                    return DECIMAL_LITERAL;
+                case 75:
+                    return INTEGER_LITERAL;
+                case 74:
+                    return LONG_LITERAL;
+                case 73:
+                    return TRANSITIVE;
+                case 72:
+                    return PROVIDES;
+                case 71:
+                    return EXPORTS;
+                case 70:
+                    return MODULE;
+                case 69:
+                    return USES;
+                case 68:
+                    return OPENS;
+                case 67:
+                    return OPEN;
+                case 66:
+                    return WITH;
+                case 65:
+                    return TO;
+                case 64:
+                    return REQUIRES;
+                case 63:
+                    return WHILE;
+                case 62:
+                    return VOLATILE;
+                case 61:
+                    return VOID;
+                case 60:
+                    return TRY;
+                case 59:
+                    return TRUE;
+                case 58:
+                    return TRANSIENT;
+                case 57:
+                    return THROWS;
+                case 56:
+                    return THROW;
+                case 55:
+                    return THIS;
+                case 54:
+                    return SYNCHRONIZED;
+                case 53:
+                    return SWITCH;
+                case 52:
+                    return SUPER;
+                case 51:
+                    return STRICTFP;
+                case 50:
+                    return STATIC;
+                case 49:
+                    return SHORT;
+                case 48:
+                    return RETURN;
+                case 47:
+                    return PUBLIC;
+                case 46:
+                    return PROTECTED;
+                case 45:
+                    return PRIVATE;
+                case 44:
+                    return PACKAGE;
+                case 43:
+                    return NULL;
+                case 42:
+                    return NEW;
+                case 41:
+                    return NATIVE;
+                case 40:
+                    return LONG;
+                case 39:
+                    return INTERFACE;
+                case 38:
+                    return INT;
+                case 37:
+                    return INSTANCEOF;
+                case 36:
+                    return IMPORT;
+                case 35:
+                    return IMPLEMENTS;
+                case 34:
+                    return IF;
+                case 33:
+                    return GOTO;
+                case 32:
+                    return FOR;
+                case 31:
+                    return FLOAT;
+                case 30:
+                    return FINALLY;
+                case 29:
+                    return FINAL;
+                case 28:
+                    return FALSE;
+                case 27:
+                    return EXTENDS;
+                case 26:
+                    return ENUM;
+                case 25:
+                    return ELSE;
+                case 24:
+                    return DOUBLE;
+                case 23:
+                    return DO;
+                case 22:
+                    return _DEFAULT;
+                case 21:
+                    return CONTINUE;
+                case 20:
+                    return CONST;
+                case 19:
+                    return CLASS;
+                case 18:
+                    return CHAR;
+                case 17:
+                    return CATCH;
+                case 16:
+                    return CASE;
+                case 15:
+                    return BYTE;
+                case 14:
+                    return BREAK;
+                case 13:
+                    return BOOLEAN;
+                case 12:
+                    return ASSERT;
+                case 11:
+                    return ABSTRACT;
+                case 10:
+                    return COMMENT_CONTENT;
+                case 9:
+                    return MULTI_LINE_COMMENT;
+                case 8:
+                    return JAVADOC_COMMENT;
+                case 7:
+                    return ENTER_MULTILINE_COMMENT;
+                case 6:
+                    return ENTER_JAVADOC_COMMENT;
+                case 5:
+                    return SINGLE_LINE_COMMENT;
+                case 4:
+                    return OLD_MAC_EOL;
+                case 3:
+                    return UNIX_EOL;
+                case 2:
+                    return WINDOWS_EOL;
+                case 1:
+                    return SPACE;
+                case 0:
+                    return EOF;
+                default:
+                    throw new IllegalArgumentException(f("Token kind %i is unknown.", kind));
+            }
+        }
+
+        public int getKind() {
+            return kind;
+        }
+    }
+
+    public JavaToken.Category getCategory() {
+        return TokenTypes.getCategory(kind);
+    }
+
+    /**
+     * Inserts newToken into the token list just before this token.
+     */
+    public void insert(JavaToken newToken) {
+        assertNotNull(newToken);
+        getPreviousToken().ifPresent(p -> {
+            p.nextToken = newToken;
+            newToken.previousToken = p;
+        });
+        previousToken = newToken;
+        newToken.nextToken = this;
+    }
+
+    /**
+     * Inserts newToken into the token list just after this token.
+     */
+    public void insertAfter(JavaToken newToken) {
+        assertNotNull(newToken);
+        getNextToken().ifPresent(n -> {
+            n.previousToken = newToken;
+            newToken.nextToken = n;
+        });
+        nextToken = newToken;
+        newToken.previousToken = this;
+    }
+
+    /**
+     * Links the tokens around the current token together, making the current token disappear from the list.
+     */
+    public void deleteToken() {
+        final Optional<JavaToken> nextToken = getNextToken();
+        final Optional<JavaToken> previousToken = getPreviousToken();
+        previousToken.ifPresent(p -> p.nextToken = nextToken.orElse(null));
+        nextToken.ifPresent(n -> n.previousToken = previousToken.orElse(null));
+    }
+
+    /**
+     * Replaces the current token with newToken.
+     */
+    public void replaceToken(JavaToken newToken) {
+        assertNotNull(newToken);
+        getPreviousToken().ifPresent(p -> {
+            p.nextToken = newToken;
+            newToken.previousToken = p;
+        });
+        getNextToken().ifPresent(n -> {
+            n.previousToken = newToken;
+            newToken.nextToken = n;
+        });
+    }
+
+    /**
+     * @return the last token in the token list.
+     */
+    public JavaToken findLastToken() {
+        JavaToken current = this;
+        while (current.getNextToken().isPresent()) {
+            current = current.getNextToken().get();
+        }
+        return current;
+    }
+
+    /**
+     * @return the first token in the token list.
+     */
+    public JavaToken findFirstToken() {
+        JavaToken current = this;
+        while (current.getPreviousToken().isPresent()) {
+            current = current.getPreviousToken().get();
+        }
+        return current;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = kind;
+        result = 31 * result + text.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        JavaToken javaToken = (JavaToken) o;
+        if (kind != javaToken.kind)
+            return false;
+        if (!text.equals(javaToken.text))
+            return false;
+        return true;
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/JavadocParser.java b/javaparser-core/src/main/java/com/github/javaparser/JavadocParser.java
new file mode 100644
index 0000000..bbe9797
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/JavadocParser.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser;
+
+import com.github.javaparser.ast.comments.JavadocComment;
+import com.github.javaparser.javadoc.Javadoc;
+import com.github.javaparser.javadoc.JavadocBlockTag;
+import com.github.javaparser.javadoc.description.JavadocDescription;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import static com.github.javaparser.utils.Utils.*;
+import static com.github.javaparser.utils.Utils.nextWord;
+
+/**
+ * The class responsible for parsing the content of JavadocComments and produce JavadocDocuments.
+ */
+class JavadocParser {
+
+    private static String BLOCK_TAG_PREFIX = "@";
+    private static Pattern BLOCK_PATTERN = Pattern.compile("^" + BLOCK_TAG_PREFIX, Pattern.MULTILINE);
+
+    public static Javadoc parse(JavadocComment comment) {
+        return parse(comment.getContent());
+    }
+
+    public static Javadoc parse(String commentContent) {
+        List<String> cleanLines = cleanLines(normalizeEolInTextBlock(commentContent, EOL));
+        int indexOfFirstBlockTag = cleanLines.stream()
+                .filter(JavadocParser::isABlockLine)
+                .map(cleanLines::indexOf)
+                .findFirst()
+                .orElse(-1);
+        List<String> blockLines;
+        String descriptionText;
+        if (indexOfFirstBlockTag == -1) {
+            descriptionText = trimRight(String.join(EOL, cleanLines));
+            blockLines = Collections.emptyList();
+        } else {
+            descriptionText = trimRight(String.join(EOL, cleanLines.subList(0, indexOfFirstBlockTag)));
+
+            //Combine cleaned lines, but only starting with the first block tag till the end
+            //In this combined string it is easier to handle multiple lines which actually belong together
+            String tagBlock = cleanLines.subList(indexOfFirstBlockTag, cleanLines.size())
+                .stream()
+                .collect(Collectors.joining(EOL));
+
+            //Split up the entire tag back again, considering now that some lines belong to the same block tag.
+            //The pattern splits the block at each new line starting with the '@' symbol, thus the symbol
+            //then needs to be added again so that the block parsers handles everything correctly.
+            blockLines = BLOCK_PATTERN
+                .splitAsStream(tagBlock)
+                .filter(STRING_NOT_EMPTY)
+                .map(s -> BLOCK_TAG_PREFIX + s)
+                .collect(Collectors.toList());
+        }
+        Javadoc document = new Javadoc(JavadocDescription.parseText(descriptionText));
+        blockLines.forEach(l -> document.addBlockTag(parseBlockTag(l)));
+        return document;
+    }
+
+    private static JavadocBlockTag parseBlockTag(String line) {
+        line = line.trim().substring(1);
+        String tagName = nextWord(line);
+        String rest = line.substring(tagName.length()).trim();
+        return new JavadocBlockTag(tagName, rest);
+    }
+
+    private static boolean isABlockLine(String line) {
+        return line.trim().startsWith(BLOCK_TAG_PREFIX);
+    }
+
+    private static String trimRight(String string) {
+        while (!string.isEmpty() && Character.isWhitespace(string.charAt(string.length() - 1))) {
+            string = string.substring(0, string.length() - 1);
+        }
+        return string;
+    }
+
+    private static List<String> cleanLines(String content) {
+        String[] lines = content.split(EOL);
+        List<String> cleanedLines = Arrays.stream(lines).map(l -> {
+            int asteriskIndex = startsWithAsterisk(l);
+            if (asteriskIndex == -1) {
+                return l;
+            } else {
+                // if a line starts with space followed by an asterisk drop to the asterisk
+                // if there is a space immediately after the asterisk drop it also
+                if (l.length() > (asteriskIndex + 1)) {
+
+                    char c = l.charAt(asteriskIndex + 1);
+                    if (c == ' ' || c == '\t') {
+                        return l.substring(asteriskIndex + 2);
+                    }
+                }
+                return l.substring(asteriskIndex + 1);
+            }
+        }).collect(Collectors.toList());
+        // lines containing only whitespace are normalized to empty lines
+        cleanedLines = cleanedLines.stream().map(l -> l.trim().isEmpty() ? "" : l).collect(Collectors.toList());
+        // if the first starts with a space, remove it
+        if (!cleanedLines.get(0).isEmpty() && (cleanedLines.get(0).charAt(0) == ' ' || cleanedLines.get(0).charAt(0) == '\t')) {
+            cleanedLines.set(0, cleanedLines.get(0).substring(1));
+        }
+        // drop empty lines at the beginning and at the end
+        while (cleanedLines.size() > 0 && cleanedLines.get(0).trim().isEmpty()) {
+            cleanedLines = cleanedLines.subList(1, cleanedLines.size());
+        }
+        while (cleanedLines.size() > 0 && cleanedLines.get(cleanedLines.size() - 1).trim().isEmpty()) {
+            cleanedLines = cleanedLines.subList(0, cleanedLines.size() - 1);
+        }
+        return cleanedLines;
+    }
+
+    // Visible for testing
+    static int startsWithAsterisk(String line) {
+        if (line.startsWith("*")) {
+            return 0;
+        } else if ((line.startsWith(" ") || line.startsWith("\t")) && line.length() > 1) {
+            int res = startsWithAsterisk(line.substring(1));
+            if (res == -1) {
+                return -1;
+            } else {
+                return 1 + res;
+            }
+        } else {
+            return -1;
+        }
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ParseProblemException.java b/javaparser-core/src/main/java/com/github/javaparser/ParseProblemException.java
new file mode 100644
index 0000000..50064dc
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ParseProblemException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser;
+
+import java.util.List;
+
+import static com.github.javaparser.utils.Utils.EOL;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+import static java.util.Collections.singletonList;
+
+/**
+ * Thrown when parsing problems occur during parsing with the static methods on JavaParser.
+ */
+public class ParseProblemException extends RuntimeException {
+    /**
+     * The problems that were encountered during parsing
+     */
+    private final List<Problem> problems;
+
+    public ParseProblemException(List<Problem> problems) {
+        super(createMessage(assertNotNull(problems)));
+        this.problems = problems;
+    }
+
+    public ParseProblemException(Throwable throwable) {
+        this(singletonList(new Problem(throwable.getMessage(), null, throwable)));
+    }
+
+    private static String createMessage(List<Problem> problems) {
+        StringBuilder message = new StringBuilder();
+        for (Problem problem : problems) {
+            message.append(problem.toString()).append(EOL);
+        }
+        return message.toString();
+    }
+
+    public List<Problem> getProblems() {
+        return problems;
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ParseResult.java b/javaparser-core/src/main/java/com/github/javaparser/ParseResult.java
new file mode 100644
index 0000000..4edc79a
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ParseResult.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser;
+
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.comments.CommentsCollection;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+import static com.github.javaparser.utils.Utils.EOL;
+
+/**
+ * The results given when parsing with an instance of JavaParser.
+ */
+public class ParseResult<T> {
+    private final T result;
+    private final List<Problem> problems;
+    private final List<JavaToken> tokens;
+    private final CommentsCollection commentsCollection;
+
+    /**
+     * General constructor.
+     *
+     * @param result the AST, or empty if it wasn't created.
+     * @param problems a list of encountered parsing problems.
+     * @param tokens the complete list of tokens that were parsed, or empty if parsing failed completely.
+     */
+    public ParseResult(T result, List<Problem> problems, List<JavaToken> tokens, CommentsCollection commentsCollection) {
+        this.commentsCollection = commentsCollection;
+        this.result = result;
+        this.problems = problems;
+        this.tokens = tokens;
+    }
+
+    /**
+     * @return if parsing was successful, meaning no errors of any kind were encountered.
+     */
+    public boolean isSuccessful() {
+        return problems.isEmpty() && result != null;
+    }
+
+    /**
+     * Calls the consumer with the result if parsing was succesful.
+     */
+    public void ifSuccessful(Consumer<T> consumer) {
+        if (isSuccessful()) {
+            consumer.accept(result);
+        }
+    }
+
+    /**
+     * @return the list of encountered parsing problems. Empty when no problems were encountered.
+     */
+    public List<Problem> getProblems() {
+        return problems;
+    }
+
+    /**
+     * @return the <code>i</code>'th encountered parsing problem. May throw <code>IndexOutOfBoundsException</code>.
+     */
+    public Problem getProblem(int i) {
+        return getProblems().get(i);
+    }
+
+    /**
+     * @return the complete list of tokens that were parsed, or empty if parsing failed completely.
+     * @deprecated lists of tokens are now kept in every node.
+     * Calling this method is comparable to calling getResult().get().getTokenRange().get()
+     */
+    @Deprecated
+    public Optional<List<JavaToken>> getTokens() {
+        return Optional.ofNullable(tokens);
+    }
+
+    /**
+     * @return the complete collection of comments encountered while parsing.
+     */
+    public Optional<CommentsCollection> getCommentsCollection() {
+        return Optional.ofNullable(commentsCollection);
+    }
+
+    /**
+     * @return the AST of the parsed source code, or empty if parsing failed completely.
+     */
+    public Optional<T> getResult() {
+        return Optional.ofNullable(result);
+    }
+
+    @Override
+    public String toString() {
+        if (isSuccessful()) {
+            return "Parsing successful";
+        }
+        StringBuilder message = new StringBuilder("Parsing failed:").append(EOL);
+        for (Problem problem : problems) {
+            message.append(problem.toString()).append(EOL);
+        }
+        return message.toString();
+    }
+
+    /**
+     * A post processor that can be added to ParserConfiguration to add some processing right after parsing.
+     */
+    public interface PostProcessor {
+        void process(ParseResult<? extends Node> result, ParserConfiguration configuration);
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ParseStart.java b/javaparser-core/src/main/java/com/github/javaparser/ParseStart.java
new file mode 100644
index 0000000..ecb562c
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ParseStart.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.ImportDeclaration;
+import com.github.javaparser.ast.PackageDeclaration;
+import com.github.javaparser.ast.body.BodyDeclaration;
+import com.github.javaparser.ast.body.Parameter;
+import com.github.javaparser.ast.expr.*;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt;
+import com.github.javaparser.ast.stmt.Statement;
+import com.github.javaparser.ast.type.ClassOrInterfaceType;
+import com.github.javaparser.ast.type.Type;
+
+/**
+ * The start production for JavaParser.
+ * Tells JavaParser what piece of Java code it can expect.
+ * For example,
+ * COMPILATION_UNIT indicates a complete Java file,
+ * and CLASS_BODY would indicate the part of a class that is within { and }.
+ *
+ * @see JavaParser#parse(ParseStart, Provider)
+ */
+@FunctionalInterface
+public interface ParseStart<R> {
+    ParseStart<CompilationUnit> COMPILATION_UNIT = GeneratedJavaParser::CompilationUnit;
+    ParseStart<BlockStmt> BLOCK = GeneratedJavaParser::BlockParseStart;
+    ParseStart<Statement> STATEMENT = GeneratedJavaParser::BlockStatementParseStart;
+    ParseStart<ImportDeclaration> IMPORT_DECLARATION = GeneratedJavaParser::ImportDeclarationParseStart;
+    ParseStart<Expression> EXPRESSION = GeneratedJavaParser::ExpressionParseStart;
+    ParseStart<AnnotationExpr> ANNOTATION = GeneratedJavaParser::AnnotationParseStart;
+    ParseStart<BodyDeclaration<?>> ANNOTATION_BODY = GeneratedJavaParser::AnnotationBodyDeclarationParseStart;
+    ParseStart<BodyDeclaration<?>> CLASS_BODY = GeneratedJavaParser::ClassOrInterfaceBodyDeclarationParseStart;
+    ParseStart<ClassOrInterfaceType> CLASS_OR_INTERFACE_TYPE = GeneratedJavaParser::ClassOrInterfaceTypeParseStart;
+    ParseStart<Type> TYPE = GeneratedJavaParser::ResultTypeParseStart;
+    ParseStart<VariableDeclarationExpr> VARIABLE_DECLARATION_EXPR = GeneratedJavaParser::VariableDeclarationExpressionParseStart;
+    ParseStart<ExplicitConstructorInvocationStmt> EXPLICIT_CONSTRUCTOR_INVOCATION_STMT = GeneratedJavaParser::ExplicitConstructorInvocationParseStart;
+    ParseStart<Name> NAME = GeneratedJavaParser::NameParseStart;
+    ParseStart<SimpleName> SIMPLE_NAME = GeneratedJavaParser::SimpleNameParseStart;
+    ParseStart<Parameter> PARAMETER = GeneratedJavaParser::ParameterParseStart;
+    ParseStart<PackageDeclaration> PACKAGE_DECLARATION = GeneratedJavaParser::PackageDeclarationParseStart;
+
+    R parse(GeneratedJavaParser parser) throws ParseException;
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ParserConfiguration.java b/javaparser-core/src/main/java/com/github/javaparser/ParserConfiguration.java
new file mode 100644
index 0000000..e5be2b8
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ParserConfiguration.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.validator.*;
+import com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter;
+import com.github.javaparser.resolution.SymbolResolver;
+import com.github.javaparser.version.Java10PostProcessor;
+import com.github.javaparser.version.Java11PostProcessor;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import static com.github.javaparser.ParserConfiguration.LanguageLevel.*;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+
+/**
+ * The configuration that is used by the parser.
+ * Note that this can be changed even when reusing the same JavaParser instance.
+ * It will pick up the changes.
+ */
+public class ParserConfiguration {
+    public enum LanguageLevel {
+        /** Does no post processing or validation. Only for people wanting the fastest parsing. */
+        RAW(null, null),
+        /** The most used Java version. */
+        POPULAR(new Java8Validator(), null),
+        /** The latest Java version that is available. */
+        CURRENT(new Java8Validator(), null),
+        /** The newest Java features supported. */
+        BLEEDING_EDGE(new Java11Validator(), new Java11PostProcessor()),
+        /** Java 1.0 */
+        JAVA_1_0(new Java1_0Validator(), null),
+        /** Java 1.1 */
+        JAVA_1_1(new Java1_1Validator(), null),
+        /** Java 1.2 */
+        JAVA_1_2(new Java1_2Validator(), null),
+        /** Java 1.3 */
+        JAVA_1_3(new Java1_3Validator(), null),
+        /** Java 1.4 */
+        JAVA_1_4(new Java1_4Validator(), null),
+        /** Java 5 */
+        JAVA_5(new Java5Validator(), null),
+        /** Java 6 */
+        JAVA_6(new Java6Validator(), null),
+        /** Java 7 */
+        JAVA_7(new Java7Validator(), null),
+        /** Java 8 */
+        JAVA_8(new Java8Validator(), null),
+        /** Java 9 */
+        JAVA_9(new Java9Validator(), null),
+        /** Java 10 */
+        JAVA_10(new Java10Validator(), new Java10PostProcessor()),
+        /** Java 11 (work in progress) */
+        JAVA_11_PREVIEW(new Java11Validator(), new Java11PostProcessor());
+
+        final Validator validator;
+        final ParseResult.PostProcessor postProcessor;
+
+        LanguageLevel(Validator validator, ParseResult.PostProcessor postProcessor) {
+            this.validator = validator;
+            this.postProcessor = postProcessor;
+        }
+    }
+
+    private boolean storeTokens = true;
+    private boolean attributeComments = true;
+    private boolean doNotAssignCommentsPrecedingEmptyLines = true;
+    private boolean doNotConsiderAnnotationsAsNodeStartForCodeAttribution = false;
+    private boolean lexicalPreservationEnabled = false;
+    private SymbolResolver symbolResolver = null;
+    private int tabSize = 1;
+    private LanguageLevel languageLevel = CURRENT;
+
+    private final List<ParseResult.PostProcessor> postProcessors = new ArrayList<>();
+
+    public ParserConfiguration() {
+        postProcessors.add((result, configuration) -> {
+            if (configuration.isLexicalPreservationEnabled()) {
+                if (configuration.isLexicalPreservationEnabled()) {
+                    result.ifSuccessful(LexicalPreservingPrinter::setup);
+                }
+            }
+        });
+        postProcessors.add((result, configuration) -> {
+            if (configuration.isAttributeComments()) {
+                result.ifSuccessful(resultNode -> result
+                        .getCommentsCollection().ifPresent(comments ->
+                                new CommentsInserter(configuration).insertComments(resultNode, comments.copy().getComments())));
+            }
+        });
+        postProcessors.add((result, configuration) -> {
+            LanguageLevel languageLevel = getLanguageLevel();
+            if (languageLevel.postProcessor != null) {
+                languageLevel.postProcessor.process(result, configuration);
+            }
+            if (languageLevel.validator != null) {
+                languageLevel.validator.accept(result.getResult().get(), new ProblemReporter(newProblem -> result.getProblems().add(newProblem)));
+            }
+        });
+        postProcessors.add((result, configuration) -> configuration.getSymbolResolver().ifPresent(symbolResolver ->
+                result.ifSuccessful(resultNode -> {
+                    if (resultNode instanceof CompilationUnit) {
+                        resultNode.setData(Node.SYMBOL_RESOLVER_KEY, symbolResolver);
+                    }
+                })
+        ));
+    }
+
+    public boolean isAttributeComments() {
+        return attributeComments;
+    }
+
+    /**
+     * Whether to run CommentsInserter, which will put the comments that were found in the source code into the comment
+     * and javadoc fields of the nodes it thinks they refer to.
+     */
+    public ParserConfiguration setAttributeComments(boolean attributeComments) {
+        this.attributeComments = attributeComments;
+        return this;
+    }
+
+    public boolean isDoNotAssignCommentsPrecedingEmptyLines() {
+        return doNotAssignCommentsPrecedingEmptyLines;
+    }
+
+    public ParserConfiguration setDoNotAssignCommentsPrecedingEmptyLines(boolean doNotAssignCommentsPrecedingEmptyLines) {
+        this.doNotAssignCommentsPrecedingEmptyLines = doNotAssignCommentsPrecedingEmptyLines;
+        return this;
+    }
+
+    public boolean isDoNotConsiderAnnotationsAsNodeStartForCodeAttribution() {
+        return doNotConsiderAnnotationsAsNodeStartForCodeAttribution;
+    }
+
+    public ParserConfiguration setDoNotConsiderAnnotationsAsNodeStartForCodeAttribution(boolean doNotConsiderAnnotationsAsNodeStartForCodeAttribution) {
+        this.doNotConsiderAnnotationsAsNodeStartForCodeAttribution = doNotConsiderAnnotationsAsNodeStartForCodeAttribution;
+        return this;
+    }
+
+    public ParserConfiguration setStoreTokens(boolean storeTokens) {
+        this.storeTokens = storeTokens;
+        if (!storeTokens) {
+            setAttributeComments(false);
+        }
+        return this;
+    }
+
+    public boolean isStoreTokens() {
+        return storeTokens;
+    }
+
+    public int getTabSize() {
+        return tabSize;
+    }
+
+    /**
+     * When a TAB character is encountered during parsing, the column position will be increased by this value.
+     * By default it is 1.
+     */
+    public ParserConfiguration setTabSize(int tabSize) {
+        this.tabSize = tabSize;
+        return this;
+    }
+
+    /**
+     * @deprecated use getLanguageLevel
+     */
+    @Deprecated
+    public Optional<Validator> getValidator() {
+        throw new IllegalStateException("method is deprecated");
+    }
+
+    /**
+     * @deprecated use setLanguageLevel, or getPostProcessors if you use a custom validator.
+     */
+    @Deprecated
+    public ParserConfiguration setValidator(Validator validator) {
+        // This whole method is a backwards compatability hack.
+        if (validator instanceof Java10Validator) {
+            setLanguageLevel(JAVA_10);
+        } else if (validator instanceof Java9Validator) {
+            setLanguageLevel(JAVA_9);
+        } else if (validator instanceof Java8Validator) {
+            setLanguageLevel(JAVA_8);
+        } else if (validator instanceof Java7Validator) {
+            setLanguageLevel(JAVA_7);
+        } else if (validator instanceof Java6Validator) {
+            setLanguageLevel(JAVA_6);
+        } else if (validator instanceof Java5Validator) {
+            setLanguageLevel(JAVA_5);
+        } else if (validator instanceof Java1_4Validator) {
+            setLanguageLevel(JAVA_1_4);
+        } else if (validator instanceof Java1_3Validator) {
+            setLanguageLevel(JAVA_1_3);
+        } else if (validator instanceof Java1_2Validator) {
+            setLanguageLevel(JAVA_1_2);
+        } else if (validator instanceof Java1_1Validator) {
+            setLanguageLevel(JAVA_1_1);
+        } else if (validator instanceof Java1_0Validator) {
+            setLanguageLevel(JAVA_1_0);
+        } else if (validator instanceof NoProblemsValidator) {
+            setLanguageLevel(RAW);
+        }
+        return this;
+    }
+
+    /**
+     * Disabled by default.
+     * When this is enabled, LexicalPreservingPrinter.print can be used to reproduce
+     * the original formatting of the file.
+     */
+    public ParserConfiguration setLexicalPreservationEnabled(boolean lexicalPreservationEnabled) {
+        this.lexicalPreservationEnabled = lexicalPreservationEnabled;
+        return this;
+    }
+
+    public boolean isLexicalPreservationEnabled() {
+        return lexicalPreservationEnabled;
+    }
+
+    /**
+     * Retrieve the SymbolResolver to be used while parsing, if any.
+     */
+    public Optional<SymbolResolver> getSymbolResolver() {
+        return Optional.ofNullable(symbolResolver);
+    }
+
+    /**
+     * Set the SymbolResolver to be injected while parsing.
+     */
+    public ParserConfiguration setSymbolResolver(SymbolResolver symbolResolver) {
+        this.symbolResolver = symbolResolver;
+        return this;
+    }
+
+    public List<ParseResult.PostProcessor> getPostProcessors() {
+        return postProcessors;
+    }
+
+    public ParserConfiguration setLanguageLevel(LanguageLevel languageLevel) {
+        this.languageLevel = assertNotNull(languageLevel);
+        return this;
+    }
+
+    public LanguageLevel getLanguageLevel() {
+        return languageLevel;
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/Position.java b/javaparser-core/src/main/java/com/github/javaparser/Position.java
new file mode 100644
index 0000000..78e95d8
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/Position.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser;
+
+import com.github.javaparser.ast.Node;
+
+import static com.github.javaparser.utils.Utils.assertNotNull;
+
+/**
+ * A position in a source file. Lines and columns start counting at 1.
+ */
+public class Position implements Comparable<Position> {
+    public final int line;
+    public final int column;
+
+    /**
+     * The first position in the file
+     */
+    public static final Position HOME = new Position(1, 1);
+
+    public Position(int line, int column) {
+        if (line < Node.ABSOLUTE_END_LINE) {
+            throw new IllegalArgumentException("Can't position at line " + line);
+        }
+        if (column < -1) {
+            throw new IllegalArgumentException("Can't position at column " + column);
+        }
+        this.line = line;
+        this.column = column;
+    }
+
+    /**
+     * Convenient factory method.
+     */
+    public static Position pos(int line, int column) {
+        return new Position(line, column);
+    }
+
+    public Position withColumn(int column) {
+        return new Position(this.line, column);
+    }
+
+    public Position withLine(int line) {
+        return new Position(line, this.column);
+    }
+
+    /**
+     * Check if the position is usable. Does not know what it is pointing at, so it can't check if the position is after
+     * the end of the source.
+     */
+    public boolean valid() {
+        return line > 0 && column > 0;
+    }
+
+    public boolean invalid() {
+        return !valid();
+    }
+
+    public Position orIfInvalid(Position anotherPosition) {
+        assertNotNull(anotherPosition);
+        if (valid() || anotherPosition.invalid()) {
+            return this;
+        }
+        return anotherPosition;
+    }
+
+    public boolean isAfter(Position position) {
+        assertNotNull(position);
+        if (position.line == Node.ABSOLUTE_BEGIN_LINE) return true;
+        if (line > position.line) {
+            return true;
+        } else if (line == position.line) {
+            return column > position.column;
+        }
+        return false;
+
+    }
+
+    public boolean isBefore(Position position) {
+        assertNotNull(position);
+        if (position.line == Node.ABSOLUTE_END_LINE) return true;
+        if (line < position.line) {
+            return true;
+        } else if (line == position.line) {
+            return column < position.column;
+        }
+        return false;
+    }
+
+    @Override
+    public int compareTo(Position o) {
+        assertNotNull(o);
+        if (isBefore(o)) {
+            return -1;
+        }
+        if (isAfter(o)) {
+            return 1;
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Position position = (Position) o;
+
+        return line == position.line && column == position.column;
+    }
+
+    @Override
+    public int hashCode() {
+        return 31 * line + column;
+    }
+
+    @Override
+    public String toString() {
+        return "(line " + line + ",col " + column + ")";
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/Problem.java b/javaparser-core/src/main/java/com/github/javaparser/Problem.java
new file mode 100644
index 0000000..2fc0532
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/Problem.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser;
+
+import java.util.Comparator;
+import java.util.Optional;
+
+import static com.github.javaparser.utils.Utils.EOL;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+
+/**
+ * A problem that was encountered during parsing.
+ */
+public class Problem {
+    private final String message;
+    private final TokenRange location;
+    private final Throwable cause;
+
+    public Problem(String message, TokenRange location, Throwable cause) {
+        assertNotNull(message);
+
+        this.message = message;
+        this.location = location;
+        this.cause = cause;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder str = new StringBuilder(getVerboseMessage());
+        if (cause != null) {
+            str.append(EOL).append("Problem stacktrace : ").append(EOL);
+            for (int i = 0; i < cause.getStackTrace().length; i++) {
+                StackTraceElement ste = cause.getStackTrace()[i];
+                str.append("  ").append(ste.toString());
+                if (i + 1 != cause.getStackTrace().length)
+                    str.append(EOL);
+            }
+        }
+        return str.toString();
+    }
+
+    /**
+     * @return the message that was passed into the constructor.
+     */
+    public String getMessage() {
+        return message;
+    }
+
+    /**
+     * @return the message plus location information.
+     */
+    public String getVerboseMessage() {
+        return getLocation().map(l -> l.getBegin().getRange().map(r -> r.begin.toString()).orElse("(line ?,col ?)") + " " + message).orElse(message);
+    }
+
+    /**
+     * @return the location that was passed into the constructor.
+     */
+    public Optional<TokenRange> getLocation() {
+        return Optional.ofNullable(location);
+    }
+
+    /**
+     * @deprecated use getLocation()
+     */
+    @Deprecated
+    public Optional<TokenRange> getRange() {
+        return getLocation();
+    }
+
+    /**
+     * @return the cause that was passed into the constructor.
+     */
+    public Optional<Throwable> getCause() {
+        return Optional.ofNullable(cause);
+    }
+
+    /**
+     * Sorts problems on position.
+     */
+    public static Comparator<Problem> PROBLEM_BY_BEGIN_POSITION = (a, b) -> {
+        final Optional<Position> aBegin= a.getLocation().flatMap(l -> l.getBegin().getRange().map(r -> r.begin));
+        final Optional<Position> bBegin = b.getLocation().flatMap(l -> l.getBegin().getRange().map(r -> r.begin));
+
+        if (aBegin.isPresent() && bBegin.isPresent()) {
+            return aBegin.get().compareTo(bBegin.get());
+        }
+        if (a.getLocation().isPresent() || b.getLocation().isPresent()) {
+            if (a.getLocation().isPresent()) {
+                return 1;
+            }
+            return -1;
+        }
+        return 0;
+    };
+
+
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/Providers.java b/javaparser-core/src/main/java/com/github/javaparser/Providers.java
new file mode 100644
index 0000000..f4b3df9
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/Providers.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser;
+
+import java.io.*;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static com.github.javaparser.utils.Utils.assertNotNull;
+
+/**
+ * Factory for providers of source code for JavaParser. Providers that have no parameter for encoding but need it will
+ * use UTF-8.
+ */
+public final class Providers {
+    public static final Charset UTF8 = Charset.forName("utf-8");
+
+    private Providers() {
+    }
+
+    public static Provider provider(Reader reader) {
+        return new StreamProvider(assertNotNull(reader));
+    }
+
+    public static Provider provider(InputStream input, Charset encoding) {
+        assertNotNull(input);
+        assertNotNull(encoding);
+        try {
+            return new StreamProvider(input, encoding.name());
+        } catch (IOException e) {
+            // The only one that is thrown is UnsupportedCharacterEncodingException,
+            // and that's a fundamental problem, so runtime exception.
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static Provider provider(InputStream input) {
+        return provider(input, UTF8);
+    }
+
+    public static Provider provider(File file, Charset encoding) throws FileNotFoundException {
+        return provider(new FileInputStream(assertNotNull(file)), assertNotNull(encoding));
+    }
+
+    public static Provider provider(File file) throws FileNotFoundException {
+        return provider(assertNotNull(file), UTF8);
+    }
+
+    public static Provider provider(Path path, Charset encoding) throws IOException {
+        return provider(Files.newInputStream(assertNotNull(path)), assertNotNull(encoding));
+    }
+
+    public static Provider provider(Path path) throws IOException {
+        return provider(assertNotNull(path), UTF8);
+    }
+
+    public static Provider provider(String source) {
+        return new StringProvider(assertNotNull(source));
+    }
+
+
+    /**
+     * Provide a Provider from the resource found in class loader with the provided encoding.<br/> As resource is
+     * accessed through a class loader, a leading "/" is not allowed in pathToResource
+     */
+    public static Provider resourceProvider(ClassLoader classLoader, String pathToResource, Charset encoding) throws IOException {
+        InputStream resourceAsStream = classLoader.getResourceAsStream(pathToResource);
+        if (resourceAsStream == null) {
+            throw new IOException("Cannot find " + pathToResource);
+        }
+        return provider(resourceAsStream, encoding);
+    }
+
+    /**
+     * Provide a Provider from the resource found in the current class loader with the provided encoding.<br/> As
+     * resource is accessed through a class loader, a leading "/" is not allowed in pathToResource
+     */
+    public static Provider resourceProvider(String pathToResource, Charset encoding) throws IOException {
+        ClassLoader classLoader = Provider.class.getClassLoader();
+        return resourceProvider(classLoader, pathToResource, encoding);
+    }
+
+    /**
+     * Provide a Provider from the resource found in the current class loader with UTF-8 encoding.<br/> As resource is
+     * accessed through a class loader, a leading "/" is not allowed in pathToResource
+     */
+    public static Provider resourceProvider(String pathToResource) throws IOException {
+        return resourceProvider(pathToResource, UTF8);
+    }
+
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/Range.java b/javaparser-core/src/main/java/com/github/javaparser/Range.java
new file mode 100644
index 0000000..dc5b329
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/Range.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser;
+
+import static com.github.javaparser.Position.pos;
+
+/**
+ * A range of characters in a source file, from "begin" to "end", including the characters at "begin" and "end".
+ */
+public class Range {
+    public final Position begin;
+    public final Position end;
+
+    public Range(Position begin, Position end) {
+        if (begin == null) {
+            throw new IllegalArgumentException("begin can't be null");
+        }
+        if (end == null) {
+            throw new IllegalArgumentException("end can't be null");
+        }
+        this.begin = begin;
+        this.end = end;
+    }
+
+    public static Range range(Position begin, Position end) {
+        return new Range(begin, end);
+    }
+
+    public static Range range(int beginLine, int beginColumn, int endLine, int endColumn) {
+        return new Range(pos(beginLine, beginColumn), pos(endLine, endColumn));
+    }
+
+    public Range withBeginColumn(int column) {
+        return range(begin.withColumn(column), end);
+    }
+
+    public Range withBeginLine(int line) {
+        return range(begin.withLine(line), end);
+    }
+
+    public Range withEndColumn(int column) {
+        return range(begin, end.withColumn(column));
+    }
+
+    public Range withEndLine(int line) {
+        return range(begin, end.withLine(line));
+    }
+
+    public Range withBegin(Position begin) {
+        return range(begin, this.end);
+    }
+
+    public Range withEnd(Position end) {
+        return range(this.begin, end);
+    }
+
+    /**
+     * As strictlyContains, but two exactly matching ranges are also considered contained one in each other.
+     */
+    public boolean contains(Range other) {
+        return (begin.isBefore(other.begin) || begin.equals(other.begin)) &&
+                (end.isAfter(other.end) || end.equals(other.end));
+    }
+
+    /**
+     * Do this strictly contains other? It means that this has to be larger than other and it has to start as other
+     * or before and end as other or after.
+     */
+    public boolean strictlyContains(Range other) {
+        return begin.isBefore(other.begin) && end.isAfter(other.end);
+    }
+
+    public boolean isBefore(Position position) {
+        return end.isBefore(position);
+    }
+
+    public boolean isAfter(Position position) {
+        return begin.isAfter(position);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Range range = (Range) o;
+
+        return begin.equals(range.begin) && end.equals(range.end);
+
+    }
+
+    @Override
+    public int hashCode() {
+        return 31 * begin.hashCode() + end.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return begin + "-" + end;
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/TokenRange.java b/javaparser-core/src/main/java/com/github/javaparser/TokenRange.java
new file mode 100644
index 0000000..c0cb038
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/TokenRange.java
@@ -0,0 +1,82 @@
+package com.github.javaparser;
+
+import java.util.Iterator;
+import java.util.Optional;
+
+import static com.github.javaparser.utils.Utils.assertNotNull;
+
+/**
+ * The range of tokens covered by this node.
+ */
+public class TokenRange implements Iterable<JavaToken> {
+    public static final TokenRange INVALID = new TokenRange(JavaToken.INVALID, JavaToken.INVALID);
+
+    private final JavaToken begin;
+    private final JavaToken end;
+
+    public TokenRange(JavaToken begin, JavaToken end) {
+        this.begin = assertNotNull(begin);
+        this.end = assertNotNull(end);
+    }
+
+    public JavaToken getBegin() {
+        return begin;
+    }
+
+    public JavaToken getEnd() {
+        return end;
+    }
+
+    public Optional<Range> toRange() {
+        if (begin.getRange().isPresent() && end.getRange().isPresent()) {
+            return Optional.of(new Range(begin.getRange().get().begin, end.getRange().get().end));
+        }
+        return Optional.empty();
+    }
+
+    public TokenRange withBegin(JavaToken begin) {
+        return new TokenRange(assertNotNull(begin), end);
+    }
+
+    public TokenRange withEnd(JavaToken end) {
+        return new TokenRange(begin, assertNotNull(end));
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        for(JavaToken t: this) {
+            result.append(t.getText());
+        }
+        return result.toString();
+    }
+
+    @Override
+    public Iterator<JavaToken> iterator() {
+        return new Iterator<JavaToken>() {
+            private boolean hasNext = true;
+            private JavaToken current = begin;
+
+            @Override
+            public boolean hasNext() {
+                return hasNext;
+            }
+
+            @Override
+            public JavaToken next() {
+                JavaToken retval = current;
+                if(current == null){
+                    throw new IllegalStateException("Attempting to move past end of range.");
+                }
+                if (current == end) {
+                    hasNext = false;
+                }
+                current = current.getNextToken().orElse(null);
+                if(current == null && hasNext){
+                    throw new IllegalStateException("End token is not linked to begin token.");
+                }
+                return retval;
+            }
+        };
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/TokenTypes.java b/javaparser-core/src/main/java/com/github/javaparser/TokenTypes.java
new file mode 100644
index 0000000..8b90aa7
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/TokenTypes.java
@@ -0,0 +1,239 @@
+package com.github.javaparser;
+
+import static com.github.javaparser.GeneratedJavaParserConstants.*;
+import static com.github.javaparser.utils.Utils.EOL;
+
+/**
+ * Complements GeneratedJavaParserConstants
+ */
+public class TokenTypes {
+    public static boolean isWhitespace(int kind) {
+        return getCategory(kind).isWhitespace();
+    }
+
+    /**
+     * @deprecated use isEndOfLineToken
+     */
+    @Deprecated
+    public static boolean isEndOfLineCharacter(int kind) {
+        return isEndOfLineToken(kind);
+    }
+
+    public static boolean isEndOfLineToken(int kind) {
+        return getCategory(kind).isEndOfLine();
+    }
+
+    public static boolean isWhitespaceOrComment(int kind) {
+        return getCategory(kind).isWhitespaceOrComment();
+    }
+
+    public static boolean isSpaceOrTab(int kind) {
+        return getCategory(kind).isWhitespaceButNotEndOfLine();
+    }
+
+    public static boolean isComment(int kind) {
+        return getCategory(kind).isComment();
+    }
+
+    /**
+     * @deprecated use eolTokenKind
+     */
+    @Deprecated
+    public static int eolToken() {
+        return eolTokenKind();
+    }
+
+    /**
+     * @return the kind of EOL token to use on the platform you're running on.
+     */
+    public static int eolTokenKind() {
+        if (EOL.equals("\n")) {
+            return UNIX_EOL;
+        }
+        if (EOL.equals("\r\n")) {
+            return WINDOWS_EOL;
+        }
+        if (EOL.equals("\r")) {
+            return OLD_MAC_EOL;
+        }
+        throw new AssertionError("Unknown EOL character sequence");
+    }
+
+    /**
+     * @return the token kind for a single space.
+     */
+    public static int spaceTokenKind() {
+        return SPACE;
+    }
+
+    /**
+     * @deprecated use spaceTokenKind
+     */
+    @Deprecated
+    public static int spaceToken() {
+        return spaceTokenKind();
+    }
+
+    /**
+     * Category of a token, a little more detailed than
+     * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.5">The JLS</a>.
+     */
+    public static JavaToken.Category getCategory(int kind) {
+        switch (kind) {
+            case WINDOWS_EOL:
+            case UNIX_EOL:
+            case OLD_MAC_EOL:
+                return JavaToken.Category.EOL;
+            case EOF:
+            case SPACE:
+            case CTRL_Z:
+                return JavaToken.Category.WHITESPACE_NO_EOL;
+            case SINGLE_LINE_COMMENT:
+            case JAVADOC_COMMENT:
+            case MULTI_LINE_COMMENT:
+                return JavaToken.Category.COMMENT;
+            case ABSTRACT:
+            case ASSERT:
+            case BOOLEAN:
+            case BREAK:
+            case BYTE:
+            case CASE:
+            case CATCH:
+            case CHAR:
+            case CLASS:
+            case CONST:
+            case CONTINUE:
+            case _DEFAULT:
+            case DO:
+            case DOUBLE:
+            case ELSE:
+            case ENUM:
+            case EXTENDS:
+            case FALSE:
+            case FINAL:
+            case FINALLY:
+            case FLOAT:
+            case FOR:
+            case GOTO:
+            case IF:
+            case IMPLEMENTS:
+            case IMPORT:
+            case INSTANCEOF:
+            case INT:
+            case INTERFACE:
+            case LONG:
+            case NATIVE:
+            case NEW:
+            case NULL:
+            case PACKAGE:
+            case PRIVATE:
+            case PROTECTED:
+            case PUBLIC:
+            case RETURN:
+            case SHORT:
+            case STATIC:
+            case STRICTFP:
+            case SUPER:
+            case SWITCH:
+            case SYNCHRONIZED:
+            case THIS:
+            case THROW:
+            case THROWS:
+            case TRANSIENT:
+            case TRUE:
+            case TRY:
+            case VOID:
+            case VOLATILE:
+            case WHILE:
+            case REQUIRES:
+            case TO:
+            case WITH:
+            case OPEN:
+            case OPENS:
+            case USES:
+            case MODULE:
+            case EXPORTS:
+            case PROVIDES:
+            case TRANSITIVE:
+                return JavaToken.Category.KEYWORD;
+            case LONG_LITERAL:
+            case INTEGER_LITERAL:
+            case DECIMAL_LITERAL:
+            case HEX_LITERAL:
+            case OCTAL_LITERAL:
+            case BINARY_LITERAL:
+            case FLOATING_POINT_LITERAL:
+            case DECIMAL_FLOATING_POINT_LITERAL:
+            case DECIMAL_EXPONENT:
+            case HEXADECIMAL_FLOATING_POINT_LITERAL:
+            case HEXADECIMAL_EXPONENT:
+            case CHARACTER_LITERAL:
+            case STRING_LITERAL:
+                return JavaToken.Category.LITERAL;
+            case IDENTIFIER:
+                return JavaToken.Category.IDENTIFIER;
+            case LPAREN:
+            case RPAREN:
+            case LBRACE:
+            case RBRACE:
+            case LBRACKET:
+            case RBRACKET:
+            case SEMICOLON:
+            case COMMA:
+            case DOT:
+            case AT:
+                return JavaToken.Category.SEPARATOR;
+            case ASSIGN:
+            case LT:
+            case BANG:
+            case TILDE:
+            case HOOK:
+            case COLON:
+            case EQ:
+            case LE:
+            case GE:
+            case NE:
+            case SC_OR:
+            case SC_AND:
+            case INCR:
+            case DECR:
+            case PLUS:
+            case MINUS:
+            case STAR:
+            case SLASH:
+            case BIT_AND:
+            case BIT_OR:
+            case XOR:
+            case REM:
+            case LSHIFT:
+            case PLUSASSIGN:
+            case MINUSASSIGN:
+            case STARASSIGN:
+            case SLASHASSIGN:
+            case ANDASSIGN:
+            case ORASSIGN:
+            case XORASSIGN:
+            case REMASSIGN:
+            case LSHIFTASSIGN:
+            case RSIGNEDSHIFTASSIGN:
+            case RUNSIGNEDSHIFTASSIGN:
+            case ELLIPSIS:
+            case ARROW:
+            case DOUBLECOLON:
+            case RUNSIGNEDSHIFT:
+            case RSIGNEDSHIFT:
+            case GT:
+                return JavaToken.Category.OPERATOR;
+            // The following are tokens that are only used internally by the lexer
+            case ENTER_JAVADOC_COMMENT:
+            case ENTER_MULTILINE_COMMENT:
+            case COMMENT_CONTENT:
+            case HEX_DIGITS:
+            case LETTER:
+            case UNICODE_ESCAPE:
+            case PART_LETTER:
+            default:
+                throw new AssertionError("Invalid token kind " + kind);
+        }
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/AccessSpecifier.java b/javaparser-core/src/main/java/com/github/javaparser/ast/AccessSpecifier.java
new file mode 100644
index 0000000..63e96b8
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/AccessSpecifier.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser.ast;
+
+/**
+ * Access specifier. Represents one of the possible levels of
+ * access permitted by the language.
+ *
+ * @author Federico Tomassetti
+ * @since July 2014
+ */
+public enum AccessSpecifier {
+
+    PUBLIC("public"),
+    PRIVATE("private"),
+    PROTECTED("protected"),
+    DEFAULT("");
+
+    private String codeRepresenation;
+
+    AccessSpecifier(String codeRepresentation) {
+        this.codeRepresenation = codeRepresentation;
+    }
+
+    public String asString() {
+        return this.codeRepresenation;
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/AllFieldsConstructor.java b/javaparser-core/src/main/java/com/github/javaparser/ast/AllFieldsConstructor.java
new file mode 100644
index 0000000..33d58e4
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/AllFieldsConstructor.java
@@ -0,0 +1,14 @@
+package com.github.javaparser.ast;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Tells tools that this is the constructor which directly initializes all fields (except "range" and "comment")
+ */
+@Target(ElementType.CONSTRUCTOR)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AllFieldsConstructor {
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/ArrayCreationLevel.java b/javaparser-core/src/main/java/com/github/javaparser/ast/ArrayCreationLevel.java
new file mode 100644
index 0000000..09148fe
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/ArrayCreationLevel.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.ast;
+
+import com.github.javaparser.ast.expr.AnnotationExpr;
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.expr.IntegerLiteralExpr;
+import com.github.javaparser.ast.nodeTypes.NodeWithAnnotations;
+import com.github.javaparser.ast.observer.ObservableProperty;
+import com.github.javaparser.ast.visitor.GenericVisitor;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.visitor.CloneVisitor;
+import com.github.javaparser.metamodel.ArrayCreationLevelMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import javax.annotation.Generated;
+import com.github.javaparser.TokenRange;
+import com.github.javaparser.metamodel.OptionalProperty;
+
+/**
+ * In <code>new int[1][2];</code> there are two ArrayCreationLevel objects,
+ * the first one contains the expression "1",
+ * the second the expression "2".
+ */
+public final class ArrayCreationLevel extends Node implements NodeWithAnnotations<ArrayCreationLevel> {
+
+    @OptionalProperty
+    private Expression dimension;
+
+    private NodeList<AnnotationExpr> annotations = new NodeList<>();
+
+    public ArrayCreationLevel() {
+        this(null, null, new NodeList<>());
+    }
+
+    public ArrayCreationLevel(int dimension) {
+        this(null, new IntegerLiteralExpr("" + dimension), new NodeList<>());
+    }
+
+    public ArrayCreationLevel(Expression dimension) {
+        this(null, dimension, new NodeList<>());
+    }
+
+    @AllFieldsConstructor
+    public ArrayCreationLevel(Expression dimension, NodeList<AnnotationExpr> annotations) {
+        this(null, dimension, annotations);
+    }
+
+    /**
+     * This constructor is used by the parser and is considered private.
+     */
+    @Generated("com.github.javaparser.generator.core.node.MainConstructorGenerator")
+    public ArrayCreationLevel(TokenRange tokenRange, Expression dimension, NodeList<AnnotationExpr> annotations) {
+        super(tokenRange);
+        setDimension(dimension);
+        setAnnotations(annotations);
+        customInitialization();
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) {
+        return v.visit(this, arg);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <A> void accept(final VoidVisitor<A> v, final A arg) {
+        v.visit(this, arg);
+    }
+
+    /**
+     * Sets the dimension
+     *
+     * @param dimension the dimension, can be null
+     * @return this, the ArrayCreationLevel
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public ArrayCreationLevel setDimension(final Expression dimension) {
+        if (dimension == this.dimension) {
+            return (ArrayCreationLevel) this;
+        }
+        notifyPropertyChange(ObservableProperty.DIMENSION, this.dimension, dimension);
+        if (this.dimension != null)
+            this.dimension.setParentNode(null);
+        this.dimension = dimension;
+        setAsParentNodeOf(dimension);
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public Optional<Expression> getDimension() {
+        return Optional.ofNullable(dimension);
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public NodeList<AnnotationExpr> getAnnotations() {
+        return annotations;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public ArrayCreationLevel setAnnotations(final NodeList<AnnotationExpr> annotations) {
+        assertNotNull(annotations);
+        if (annotations == this.annotations) {
+            return (ArrayCreationLevel) this;
+        }
+        notifyPropertyChange(ObservableProperty.ANNOTATIONS, this.annotations, annotations);
+        if (this.annotations != null)
+            this.annotations.setParentNode(null);
+        this.annotations = annotations;
+        setAsParentNodeOf(annotations);
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public ArrayCreationLevel removeDimension() {
+        return setDimension((Expression) null);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public boolean remove(Node node) {
+        if (node == null)
+            return false;
+        for (int i = 0; i < annotations.size(); i++) {
+            if (annotations.get(i) == node) {
+                annotations.remove(i);
+                return true;
+            }
+        }
+        if (dimension != null) {
+            if (node == dimension) {
+                removeDimension();
+                return true;
+            }
+        }
+        return super.remove(node);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.CloneGenerator")
+    public ArrayCreationLevel clone() {
+        return (ArrayCreationLevel) accept(new CloneVisitor(), null);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.GetMetaModelGenerator")
+    public ArrayCreationLevelMetaModel getMetaModel() {
+        return JavaParserMetaModel.arrayCreationLevelMetaModel;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.ReplaceMethodGenerator")
+    public boolean replace(Node node, Node replacementNode) {
+        if (node == null)
+            return false;
+        for (int i = 0; i < annotations.size(); i++) {
+            if (annotations.get(i) == node) {
+                annotations.set(i, (AnnotationExpr) replacementNode);
+                return true;
+            }
+        }
+        if (dimension != null) {
+            if (node == dimension) {
+                setDimension((Expression) replacementNode);
+                return true;
+            }
+        }
+        return super.replace(node, replacementNode);
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/CompilationUnit.java b/javaparser-core/src/main/java/com/github/javaparser/ast/CompilationUnit.java
new file mode 100644
index 0000000..fd8bb20
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/CompilationUnit.java
@@ -0,0 +1,694 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.ast;
+
+import com.github.javaparser.JavaParser;
+import com.github.javaparser.ParseResult;
+import com.github.javaparser.ParseStart;
+import com.github.javaparser.TokenRange;
+import com.github.javaparser.ast.body.AnnotationDeclaration;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.EnumDeclaration;
+import com.github.javaparser.ast.body.TypeDeclaration;
+import com.github.javaparser.ast.comments.Comment;
+import com.github.javaparser.ast.comments.JavadocComment;
+import com.github.javaparser.ast.expr.Name;
+import com.github.javaparser.ast.modules.ModuleDeclaration;
+import com.github.javaparser.ast.nodeTypes.NodeWithName;
+import com.github.javaparser.ast.observer.ObservableProperty;
+import com.github.javaparser.ast.visitor.CloneVisitor;
+import com.github.javaparser.ast.visitor.GenericVisitor;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+import com.github.javaparser.metamodel.CompilationUnitMetaModel;
+import com.github.javaparser.metamodel.InternalProperty;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import com.github.javaparser.metamodel.OptionalProperty;
+import com.github.javaparser.printer.PrettyPrinter;
+import com.github.javaparser.utils.ClassUtils;
+import com.github.javaparser.utils.CodeGenerationUtils;
+import com.github.javaparser.utils.Utils;
+import javax.annotation.Generated;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import static com.github.javaparser.JavaParser.parseName;
+import static com.github.javaparser.Providers.UTF8;
+import static com.github.javaparser.Providers.provider;
+import static com.github.javaparser.utils.CodeGenerationUtils.subtractPaths;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+import com.github.javaparser.ast.Node;
+
+/**
+ * <p>
+ * This class represents the entire compilation unit. Each java file denotes a
+ * compilation unit.
+ * </p>
+ * A compilation unit start with an optional package declaration,
+ * followed by zero or more import declarations,
+ * followed by zero or more type declarations.
+ *
+ * @author Julio Vilmar Gesser
+ * @see PackageDeclaration
+ * @see ImportDeclaration
+ * @see TypeDeclaration
+ * @see Storage
+ */
+public final class CompilationUnit extends Node {
+
+    @OptionalProperty
+    private PackageDeclaration packageDeclaration;
+
+    private NodeList<ImportDeclaration> imports;
+
+    private NodeList<TypeDeclaration<?>> types;
+
+    @OptionalProperty
+    private ModuleDeclaration module;
+
+    @InternalProperty
+    private Storage storage;
+
+    public CompilationUnit() {
+        this(null, null, new NodeList<>(), new NodeList<>(), null);
+    }
+
+    public CompilationUnit(String packageDeclaration) {
+        this(null, new PackageDeclaration(new Name(packageDeclaration)), new NodeList<>(), new NodeList<>(), null);
+    }
+
+    @AllFieldsConstructor
+    public CompilationUnit(PackageDeclaration packageDeclaration, NodeList<ImportDeclaration> imports, NodeList<TypeDeclaration<?>> types, ModuleDeclaration module) {
+        this(null, packageDeclaration, imports, types, module);
+    }
+
+    /**
+     * This constructor is used by the parser and is considered private.
+     */
+    @Generated("com.github.javaparser.generator.core.node.MainConstructorGenerator")
+    public CompilationUnit(TokenRange tokenRange, PackageDeclaration packageDeclaration, NodeList<ImportDeclaration> imports, NodeList<TypeDeclaration<?>> types, ModuleDeclaration module) {
+        super(tokenRange);
+        setPackageDeclaration(packageDeclaration);
+        setImports(imports);
+        setTypes(types);
+        setModule(module);
+        customInitialization();
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) {
+        return v.visit(this, arg);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <A> void accept(final VoidVisitor<A> v, final A arg) {
+        v.visit(this, arg);
+    }
+
+    /**
+     * Return a list containing all comments declared in this compilation unit.
+     * Including javadocs, line comments and block comments of all types,
+     * inner-classes and other members.<br>
+     * If there is no comment, an empty list is returned.
+     *
+     * @return list with all comments of this compilation unit.
+     * @see JavadocComment
+     * @see com.github.javaparser.ast.comments.LineComment
+     * @see com.github.javaparser.ast.comments.BlockComment
+     */
+    public List<Comment> getComments() {
+        return this.getAllContainedComments();
+    }
+
+    /**
+     * Retrieves the list of imports declared in this compilation unit or
+     * <code>null</code> if there is no import.
+     *
+     * @return the list of imports or <code>none</code> if there is no import
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public NodeList<ImportDeclaration> getImports() {
+        return imports;
+    }
+
+    public ImportDeclaration getImport(int i) {
+        return getImports().get(i);
+    }
+
+    /**
+     * Retrieves the package declaration of this compilation unit.<br>
+     * If this compilation unit has no package declaration (default package),
+     * <code>Optional.none()</code> is returned.
+     *
+     * @return the package declaration or <code>none</code>
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public Optional<PackageDeclaration> getPackageDeclaration() {
+        return Optional.ofNullable(packageDeclaration);
+    }
+
+    /**
+     * Return the list of top level types declared in this compilation unit.<br>
+     * If there are no types declared, <code>none</code> is returned.
+     *
+     * @return the list of types or <code>none</code> null if there is no type
+     * @see AnnotationDeclaration
+     * @see ClassOrInterfaceDeclaration
+     * @see EnumDeclaration
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public NodeList<TypeDeclaration<?>> getTypes() {
+        return types;
+    }
+
+    /**
+     * Convenience method that wraps <code>getTypes()</code>.<br>
+     * If <code>i</code> is out of bounds, throws <code>IndexOutOfBoundsException.</code>
+     *
+     * @param i the index of the type declaration to retrieve
+     */
+    public TypeDeclaration<?> getType(int i) {
+        return getTypes().get(i);
+    }
+
+    /**
+     * Sets the list of imports of this compilation unit. The list is initially
+     * <code>null</code>.
+     *
+     * @param imports the list of imports
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public CompilationUnit setImports(final NodeList<ImportDeclaration> imports) {
+        assertNotNull(imports);
+        if (imports == this.imports) {
+            return (CompilationUnit) this;
+        }
+        notifyPropertyChange(ObservableProperty.IMPORTS, this.imports, imports);
+        if (this.imports != null)
+            this.imports.setParentNode(null);
+        this.imports = imports;
+        setAsParentNodeOf(imports);
+        return this;
+    }
+
+    public CompilationUnit setImport(int i, ImportDeclaration imports) {
+        getImports().set(i, imports);
+        return this;
+    }
+
+    public CompilationUnit addImport(ImportDeclaration imports) {
+        getImports().add(imports);
+        return this;
+    }
+
+    /**
+     * Sets or clear the package declarations of this compilation unit.
+     *
+     * @param packageDeclaration the packageDeclaration declaration to set or <code>null</code> to default package
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public CompilationUnit setPackageDeclaration(final PackageDeclaration packageDeclaration) {
+        if (packageDeclaration == this.packageDeclaration) {
+            return (CompilationUnit) this;
+        }
+        notifyPropertyChange(ObservableProperty.PACKAGE_DECLARATION, this.packageDeclaration, packageDeclaration);
+        if (this.packageDeclaration != null)
+            this.packageDeclaration.setParentNode(null);
+        this.packageDeclaration = packageDeclaration;
+        setAsParentNodeOf(packageDeclaration);
+        return this;
+    }
+
+    /**
+     * Sets the list of types declared in this compilation unit.
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public CompilationUnit setTypes(final NodeList<TypeDeclaration<?>> types) {
+        assertNotNull(types);
+        if (types == this.types) {
+            return (CompilationUnit) this;
+        }
+        notifyPropertyChange(ObservableProperty.TYPES, this.types, types);
+        if (this.types != null)
+            this.types.setParentNode(null);
+        this.types = types;
+        setAsParentNodeOf(types);
+        return this;
+    }
+
+    public CompilationUnit setType(int i, TypeDeclaration<?> type) {
+        NodeList<TypeDeclaration<?>> copy = new NodeList<>();
+        copy.addAll(getTypes());
+        getTypes().set(i, type);
+        notifyPropertyChange(ObservableProperty.TYPES, copy, types);
+        return this;
+    }
+
+    public CompilationUnit addType(TypeDeclaration<?> type) {
+        NodeList<TypeDeclaration<?>> copy = new NodeList<>();
+        copy.addAll(getTypes());
+        getTypes().add(type);
+        notifyPropertyChange(ObservableProperty.TYPES, copy, types);
+        return this;
+    }
+
+    /**
+     * sets the package declaration of this compilation unit
+     *
+     * @param name the name of the package
+     * @return this, the {@link CompilationUnit}
+     */
+    public CompilationUnit setPackageDeclaration(String name) {
+        setPackageDeclaration(new PackageDeclaration(parseName(name)));
+        return this;
+    }
+
+    /**
+     * Add an import to the list of {@link ImportDeclaration} of this compilation unit<br>
+     * shorthand for {@link #addImport(String, boolean, boolean)} with name,false,false
+     *
+     * @param name the import name
+     * @return this, the {@link CompilationUnit}
+     */
+    public CompilationUnit addImport(String name) {
+        return addImport(name, false, false);
+    }
+
+    /**
+     * Add an import to the list of {@link ImportDeclaration} of this compilation unit<br>
+     * shorthand for {@link #addImport(String)} with clazz.getName()
+     *
+     * @param clazz the class to import
+     * @return this, the {@link CompilationUnit}
+     * @throws RuntimeException if clazz is an anonymous or local class
+     */
+    public CompilationUnit addImport(Class<?> clazz) {
+        if (ClassUtils.isPrimitiveOrWrapper(clazz) || clazz.getName().startsWith("java.lang"))
+            return this;
+        else if (clazz.isMemberClass())
+            return addImport(clazz.getName().replace("$", "."));
+        else if (clazz.isArray() && !ClassUtils.isPrimitiveOrWrapper(clazz.getComponentType()) && !clazz.getComponentType().getName().startsWith("java.lang"))
+            return addImport(clazz.getComponentType().getName());
+        else if (clazz.isAnonymousClass() || clazz.isLocalClass())
+            throw new RuntimeException(clazz.getName() + " is an anonymous or local class therefore it can't be added with addImport");
+        return addImport(clazz.getName());
+    }
+
+    /**
+     * Add an import to the list of {@link ImportDeclaration} of this compilation unit<br>
+     * <b>This method check if no import with the same name is already in the list</b>
+     *
+     * @param name the import name
+     * @param isStatic is it an "import static"
+     * @param isAsterisk does the import end with ".*"
+     * @return this, the {@link CompilationUnit}
+     */
+    public CompilationUnit addImport(String name, boolean isStatic, boolean isAsterisk) {
+        final StringBuilder i = new StringBuilder("import ");
+        if (isStatic) {
+            i.append("static ");
+        }
+        i.append(name);
+        if (isAsterisk) {
+            i.append(".*");
+        }
+        i.append(";");
+        ImportDeclaration importDeclaration = JavaParser.parseImport(i.toString());
+        if (getImports().stream().anyMatch(im -> im.toString().equals(importDeclaration.toString())))
+            return this;
+        else {
+            getImports().add(importDeclaration);
+            return this;
+        }
+    }
+
+    /**
+     * Add a public class to the types of this compilation unit
+     *
+     * @param name the class name
+     * @return the newly created class
+     */
+    public ClassOrInterfaceDeclaration addClass(String name) {
+        return addClass(name, Modifier.PUBLIC);
+    }
+
+    /**
+     * Add a class to the types of this compilation unit
+     *
+     * @param name the class name
+     * @param modifiers the modifiers (like Modifier.PUBLIC)
+     * @return the newly created class
+     */
+    public ClassOrInterfaceDeclaration addClass(String name, Modifier... modifiers) {
+        ClassOrInterfaceDeclaration classOrInterfaceDeclaration = new ClassOrInterfaceDeclaration(Arrays.stream(modifiers).collect(Collectors.toCollection(() -> EnumSet.noneOf(Modifier.class))), false, name);
+        getTypes().add(classOrInterfaceDeclaration);
+        return classOrInterfaceDeclaration;
+    }
+
+    /**
+     * Add a public interface class to the types of this compilation unit
+     *
+     * @param name the interface name
+     * @return the newly created class
+     */
+    public ClassOrInterfaceDeclaration addInterface(String name) {
+        return addInterface(name, Modifier.PUBLIC);
+    }
+
+    /**
+     * Add an interface to the types of this compilation unit
+     *
+     * @param name the interface name
+     * @param modifiers the modifiers (like Modifier.PUBLIC)
+     * @return the newly created class
+     */
+    public ClassOrInterfaceDeclaration addInterface(String name, Modifier... modifiers) {
+        ClassOrInterfaceDeclaration classOrInterfaceDeclaration = new ClassOrInterfaceDeclaration(Arrays.stream(modifiers).collect(Collectors.toCollection(() -> EnumSet.noneOf(Modifier.class))), true, name);
+        getTypes().add(classOrInterfaceDeclaration);
+        return classOrInterfaceDeclaration;
+    }
+
+    /**
+     * Add a public enum to the types of this compilation unit
+     *
+     * @param name the enum name
+     * @return the newly created class
+     */
+    public EnumDeclaration addEnum(String name) {
+        return addEnum(name, Modifier.PUBLIC);
+    }
+
+    /**
+     * Add an enum to the types of this compilation unit
+     *
+     * @param name the enum name
+     * @param modifiers the modifiers (like Modifier.PUBLIC)
+     * @return the newly created class
+     */
+    public EnumDeclaration addEnum(String name, Modifier... modifiers) {
+        EnumDeclaration enumDeclaration = new EnumDeclaration(Arrays.stream(modifiers).collect(Collectors.toCollection(() -> EnumSet.noneOf(Modifier.class))), name);
+        getTypes().add(enumDeclaration);
+        return enumDeclaration;
+    }
+
+    /**
+     * Add a public annotation declaration to the types of this compilation unit
+     *
+     * @param name the annotation name
+     * @return the newly created class
+     */
+    public AnnotationDeclaration addAnnotationDeclaration(String name) {
+        return addAnnotationDeclaration(name, Modifier.PUBLIC);
+    }
+
+    /**
+     * Add an annotation declaration to the types of this compilation unit
+     *
+     * @param name the annotation name
+     * @param modifiers the modifiers (like Modifier.PUBLIC)
+     * @return the newly created class
+     */
+    public AnnotationDeclaration addAnnotationDeclaration(String name, Modifier... modifiers) {
+        AnnotationDeclaration annotationDeclaration = new AnnotationDeclaration(Arrays.stream(modifiers).collect(Collectors.toCollection(() -> EnumSet.noneOf(Modifier.class))), name);
+        getTypes().add(annotationDeclaration);
+        return annotationDeclaration;
+    }
+
+    /**
+     * Try to get a top level class declaration by its name
+     *
+     * @param className the class name (case-sensitive)
+     */
+    public Optional<ClassOrInterfaceDeclaration> getClassByName(String className) {
+        return getTypes().stream().filter(type -> type.getNameAsString().equals(className) && type instanceof ClassOrInterfaceDeclaration && !((ClassOrInterfaceDeclaration) type).isInterface()).findFirst().map(t -> (ClassOrInterfaceDeclaration) t);
+    }
+
+    /**
+     * Try to get a top level interface declaration by its name
+     *
+     * @param interfaceName the interface name (case-sensitive)
+     */
+    public Optional<ClassOrInterfaceDeclaration> getInterfaceByName(String interfaceName) {
+        return getTypes().stream().filter(type -> type.getNameAsString().equals(interfaceName) && type instanceof ClassOrInterfaceDeclaration && ((ClassOrInterfaceDeclaration) type).isInterface()).findFirst().map(t -> (ClassOrInterfaceDeclaration) t);
+    }
+
+    /**
+     * Try to get a top level enum declaration by its name
+     *
+     * @param enumName the enum name (case-sensitive)
+     */
+    public Optional<EnumDeclaration> getEnumByName(String enumName) {
+        return getTypes().stream().filter(type -> type.getNameAsString().equals(enumName) && type instanceof EnumDeclaration).findFirst().map(t -> (EnumDeclaration) t);
+    }
+
+    /**
+     * @return the name that the primary type in this file should have, according to the filename in {@link Storage#getFileName()}.
+     * Empty if no file information is present (when this compilation unit wasn't parsed from a file.)
+     */
+    public Optional<String> getPrimaryTypeName() {
+        return getStorage().map(Storage::getFileName).map(Utils::removeFileExtension);
+    }
+
+    /**
+     * @return the type whose name corresponds to the file name.
+     * Empty if no file information is present (when this compilation unit wasn't parsed from a file.)
+     * If for some strange reason there are multiple types of this name, the first one is returned.
+     */
+    public Optional<TypeDeclaration<?>> getPrimaryType() {
+        return getPrimaryTypeName().flatMap(name -> getTypes().stream().filter(t -> t.getNameAsString().equals(name)).findFirst());
+    }
+
+    /**
+     * Try to get a top level annotation type declaration by its name
+     *
+     * @param annotationName the annotation name (case-sensitive)
+     */
+    public Optional<AnnotationDeclaration> getAnnotationDeclarationByName(String annotationName) {
+        return getTypes().stream().filter(type -> type.getNameAsString().equals(annotationName) && type instanceof AnnotationDeclaration).findFirst().map(t -> (AnnotationDeclaration) t);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public boolean remove(Node node) {
+        if (node == null)
+            return false;
+        for (int i = 0; i < imports.size(); i++) {
+            if (imports.get(i) == node) {
+                imports.remove(i);
+                return true;
+            }
+        }
+        if (module != null) {
+            if (node == module) {
+                removeModule();
+                return true;
+            }
+        }
+        if (packageDeclaration != null) {
+            if (node == packageDeclaration) {
+                removePackageDeclaration();
+                return true;
+            }
+        }
+        for (int i = 0; i < types.size(); i++) {
+            if (types.get(i) == node) {
+                types.remove(i);
+                return true;
+            }
+        }
+        return super.remove(node);
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public CompilationUnit removePackageDeclaration() {
+        return setPackageDeclaration((PackageDeclaration) null);
+    }
+
+    /**
+     * @return the module declared in this compilation unit.
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public Optional<ModuleDeclaration> getModule() {
+        return Optional.ofNullable(module);
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public CompilationUnit setModule(final ModuleDeclaration module) {
+        if (module == this.module) {
+            return (CompilationUnit) this;
+        }
+        notifyPropertyChange(ObservableProperty.MODULE, this.module, module);
+        if (this.module != null)
+            this.module.setParentNode(null);
+        this.module = module;
+        setAsParentNodeOf(module);
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public CompilationUnit removeModule() {
+        return setModule((ModuleDeclaration) null);
+    }
+
+    /**
+     * @return information about where this compilation unit was loaded from, or empty if it wasn't loaded from a file.
+     */
+    public Optional<Storage> getStorage() {
+        return Optional.ofNullable(storage);
+    }
+
+    public CompilationUnit setStorage(Path path) {
+        this.storage = new Storage(this, path);
+        return this;
+    }
+
+    /**
+     * Information about where this compilation unit was loaded from.
+     * This class only stores the absolute location.
+     * For more flexibility use SourceRoot.
+     */
+    public static class Storage {
+
+        private final CompilationUnit compilationUnit;
+
+        private final Path path;
+
+        private Storage(CompilationUnit compilationUnit, Path path) {
+            this.compilationUnit = compilationUnit;
+            this.path = path.toAbsolutePath();
+        }
+
+        /**
+         * @return the path to the source for this CompilationUnit
+         */
+        public Path getPath() {
+            return path;
+        }
+
+        /**
+         * @return the CompilationUnit this Storage is about.
+         */
+        public CompilationUnit getCompilationUnit() {
+            return compilationUnit;
+        }
+
+        /**
+         * @return the source root directory, calculated from the path of this compiation unit, and the package
+         * declaration of this compilation unit. If the package declaration is invalid (when it does not match the end
+         * of the path) a RuntimeException is thrown.
+         */
+        public Path getSourceRoot() {
+            final Optional<String> pkgAsString = compilationUnit.getPackageDeclaration().map(NodeWithName::getNameAsString);
+            return pkgAsString.map(p -> Paths.get(CodeGenerationUtils.packageToPath(p))).map(pkg -> subtractPaths(getDirectory(), pkg)).orElse(getDirectory());
+        }
+
+        public String getFileName() {
+            return path.getFileName().toString();
+        }
+
+        public Path getDirectory() {
+            return path.getParent();
+        }
+
+        /**
+         * Saves the compilation unit to its original location
+         */
+        public void save() {
+            save(cu -> new PrettyPrinter().print(cu));
+        }
+
+        /**
+         * Saves a compilation unit to its original location with formatting according to the function
+         * passed as a parameter.
+         *
+         * @param makeOutput a function that formats the compilation unit
+         */
+        public void save(Function<CompilationUnit, String> makeOutput) {
+            try {
+                Files.createDirectories(path.getParent());
+                final String code = makeOutput.apply(getCompilationUnit());
+                Files.write(path, code.getBytes(UTF8));
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        public ParseResult<CompilationUnit> reparse(JavaParser javaParser) {
+            try {
+                return javaParser.parse(ParseStart.COMPILATION_UNIT, provider(getPath()));
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.CloneGenerator")
+    public CompilationUnit clone() {
+        return (CompilationUnit) accept(new CloneVisitor(), null);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.GetMetaModelGenerator")
+    public CompilationUnitMetaModel getMetaModel() {
+        return JavaParserMetaModel.compilationUnitMetaModel;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.ReplaceMethodGenerator")
+    public boolean replace(Node node, Node replacementNode) {
+        if (node == null)
+            return false;
+        for (int i = 0; i < imports.size(); i++) {
+            if (imports.get(i) == node) {
+                imports.set(i, (ImportDeclaration) replacementNode);
+                return true;
+            }
+        }
+        if (module != null) {
+            if (node == module) {
+                setModule((ModuleDeclaration) replacementNode);
+                return true;
+            }
+        }
+        if (packageDeclaration != null) {
+            if (node == packageDeclaration) {
+                setPackageDeclaration((PackageDeclaration) replacementNode);
+                return true;
+            }
+        }
+        for (int i = 0; i < types.size(); i++) {
+            if (types.get(i) == node) {
+                types.set(i, (TypeDeclaration) replacementNode);
+                return true;
+            }
+        }
+        return super.replace(node, replacementNode);
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/DataKey.java b/javaparser-core/src/main/java/com/github/javaparser/ast/DataKey.java
new file mode 100644
index 0000000..2f2115d
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/DataKey.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser.ast;
+
+/**
+ * A key to a piece of data associated with a {@link Node} at runtime.
+ * The key contains type information that can be used to check the
+ * type of any user data value for the key when the value is set. DataKey is abstract in order to
+ * force the creation of a subtype. That subtype is used to test for identity when looking for the
+ * user data because actual object identity would suffer from problems under serialization.
+ * So, the correct way to declare a DataKey is like this:
+ * <p>
+ * <pre>
+ * <code>
+ * public static final DataKey&lt;Role&gt; ROLE = new DataKey&lt;Role&gt;() { };
+ * </code>
+ * </pre>
+ * <p>
+ * This code was taken from the <a href="http://wicket.apache.org/">Wicket project</a>.
+ *
+ * @param <T> The type of the object which is stored
+ * @see Node#getData(DataKey)
+ */
+public abstract class DataKey<T> {
+    @Override
+    public int hashCode() {
+        return getClass().hashCode();
+    }
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        return obj != null && getClass().equals(obj.getClass());
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/ImportDeclaration.java b/javaparser-core/src/main/java/com/github/javaparser/ast/ImportDeclaration.java
new file mode 100644
index 0000000..88ab096
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/ImportDeclaration.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ * 
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License 
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.ast;
+
+import com.github.javaparser.JavaParser;
+import com.github.javaparser.ast.expr.Name;
+import com.github.javaparser.ast.expr.SimpleName;
+import com.github.javaparser.ast.nodeTypes.NodeWithName;
+import com.github.javaparser.ast.observer.ObservableProperty;
+import com.github.javaparser.ast.visitor.GenericVisitor;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+import static com.github.javaparser.JavaParser.*;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.visitor.CloneVisitor;
+import com.github.javaparser.metamodel.ImportDeclarationMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import javax.annotation.Generated;
+import com.github.javaparser.TokenRange;
+
+/**
+ * An import declaration.
+ * <br/><code>import com.github.javaparser.JavaParser;</code>
+ * <br/><code>import com.github.javaparser.*;</code>
+ * <br/><code>import com.github.javaparser.JavaParser.*; </code>
+ * <br/><code>import static com.github.javaparser.JavaParser.*;</code>
+ * <br/><code>import static com.github.javaparser.JavaParser.parse;</code>
+ *
+ * <p>The name does not include the asterisk or the static keyword.</p>
+ * @author Julio Vilmar Gesser
+ */
+public final class ImportDeclaration extends Node implements NodeWithName<ImportDeclaration> {
+
+    private Name name;
+
+    private boolean isStatic;
+
+    private boolean isAsterisk;
+
+    private ImportDeclaration() {
+        this(null, new Name(), false, false);
+    }
+
+    public ImportDeclaration(String name, boolean isStatic, boolean isAsterisk) {
+        this(null, parseName(name), isStatic, isAsterisk);
+    }
+
+    @AllFieldsConstructor
+    public ImportDeclaration(Name name, boolean isStatic, boolean isAsterisk) {
+        this(null, name, isStatic, isAsterisk);
+    }
+
+    /**
+     * This constructor is used by the parser and is considered private.
+     */
+    @Generated("com.github.javaparser.generator.core.node.MainConstructorGenerator")
+    public ImportDeclaration(TokenRange tokenRange, Name name, boolean isStatic, boolean isAsterisk) {
+        super(tokenRange);
+        setName(name);
+        setStatic(isStatic);
+        setAsterisk(isAsterisk);
+        customInitialization();
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) {
+        return v.visit(this, arg);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <A> void accept(final VoidVisitor<A> v, final A arg) {
+        v.visit(this, arg);
+    }
+
+    /**
+     * Retrieves the name of the import (.* is not included.)
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public Name getName() {
+        return name;
+    }
+
+    /**
+     * Return if the import ends with "*".
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public boolean isAsterisk() {
+        return isAsterisk;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public boolean isStatic() {
+        return isStatic;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public ImportDeclaration setAsterisk(final boolean isAsterisk) {
+        if (isAsterisk == this.isAsterisk) {
+            return (ImportDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.ASTERISK, this.isAsterisk, isAsterisk);
+        this.isAsterisk = isAsterisk;
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public ImportDeclaration setName(final Name name) {
+        assertNotNull(name);
+        if (name == this.name) {
+            return (ImportDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.NAME, this.name, name);
+        if (this.name != null)
+            this.name.setParentNode(null);
+        this.name = name;
+        setAsParentNodeOf(name);
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public ImportDeclaration setStatic(final boolean isStatic) {
+        if (isStatic == this.isStatic) {
+            return (ImportDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.STATIC, this.isStatic, isStatic);
+        this.isStatic = isStatic;
+        return this;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public boolean remove(Node node) {
+        if (node == null)
+            return false;
+        return super.remove(node);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.CloneGenerator")
+    public ImportDeclaration clone() {
+        return (ImportDeclaration) accept(new CloneVisitor(), null);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.GetMetaModelGenerator")
+    public ImportDeclarationMetaModel getMetaModel() {
+        return JavaParserMetaModel.importDeclarationMetaModel;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.ReplaceMethodGenerator")
+    public boolean replace(Node node, Node replacementNode) {
+        if (node == null)
+            return false;
+        if (node == name) {
+            setName((Name) replacementNode);
+            return true;
+        }
+        return super.replace(node, replacementNode);
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/Modifier.java b/javaparser-core/src/main/java/com/github/javaparser/ast/Modifier.java
new file mode 100644
index 0000000..b6d0309
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/Modifier.java
@@ -0,0 +1,72 @@
+/*

+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.

+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.

+ *

+ * This file is part of JavaParser.

+ *

+ * JavaParser can be used either under the terms of

+ * a) the GNU Lesser General Public License as published by

+ *     the Free Software Foundation, either version 3 of the License, or

+ *     (at your option) any later version.

+ * b) the terms of the Apache License

+ *

+ * You should have received a copy of both licenses in LICENCE.LGPL and

+ * LICENCE.APACHE. Please refer to those files for details.

+ *

+ * JavaParser is distributed in the hope that it will be useful,

+ * but WITHOUT ANY WARRANTY; without even the implied warranty of

+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ * GNU Lesser General Public License for more details.

+ */

+

+package com.github.javaparser.ast;

+

+import java.util.EnumSet;

+

+/**

+ * One of the modifiers known in Java.

+ */

+public enum Modifier {

+    PUBLIC,

+    PROTECTED,

+    PRIVATE,

+    ABSTRACT,

+    STATIC,

+    FINAL,

+    TRANSIENT,

+    VOLATILE,

+    SYNCHRONIZED,

+    NATIVE,

+    STRICTFP,

+    TRANSITIVE,

+    DEFAULT;

+

+    final String codeRepresentation;

+

+    Modifier() {

+        this.codeRepresentation = name().toLowerCase();

+    }

+

+    /**

+     * @return the keyword represented by this modifier.

+     */

+    public String asString() {

+        return codeRepresentation;

+    }

+

+    public EnumSet<Modifier> toEnumSet() {

+        return EnumSet.of(this);

+    }

+

+    public static AccessSpecifier getAccessSpecifier(EnumSet<Modifier> modifiers) {

+        if (modifiers.contains(Modifier.PUBLIC)) {

+            return AccessSpecifier.PUBLIC;

+        } else if (modifiers.contains(Modifier.PROTECTED)) {

+            return AccessSpecifier.PROTECTED;

+        } else if (modifiers.contains(Modifier.PRIVATE)) {

+            return AccessSpecifier.PRIVATE;

+        } else {

+            return AccessSpecifier.DEFAULT;

+        }

+    }

+}

diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/Node.java b/javaparser-core/src/main/java/com/github/javaparser/ast/Node.java
new file mode 100644
index 0000000..98d0bbc
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/Node.java
@@ -0,0 +1,1004 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.ast;
+
+import com.github.javaparser.HasParentNode;
+import com.github.javaparser.Range;
+import com.github.javaparser.TokenRange;
+import com.github.javaparser.ast.comments.BlockComment;
+import com.github.javaparser.ast.comments.Comment;
+import com.github.javaparser.ast.comments.LineComment;
+import com.github.javaparser.ast.nodeTypes.NodeWithRange;
+import com.github.javaparser.ast.nodeTypes.NodeWithTokenRange;
+import com.github.javaparser.ast.observer.AstObserver;
+import com.github.javaparser.ast.observer.ObservableProperty;
+import com.github.javaparser.ast.observer.PropagatingAstObserver;
+import com.github.javaparser.ast.visitor.CloneVisitor;
+import com.github.javaparser.ast.visitor.EqualsVisitor;
+import com.github.javaparser.ast.visitor.HashCodeVisitor;
+import com.github.javaparser.ast.visitor.Visitable;
+import com.github.javaparser.metamodel.*;
+import com.github.javaparser.printer.PrettyPrinter;
+import com.github.javaparser.printer.PrettyPrinterConfiguration;
+import com.github.javaparser.resolution.SymbolResolver;
+import javax.annotation.Generated;
+import java.util.*;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import static com.github.javaparser.ast.Node.Parsedness.PARSED;
+import static com.github.javaparser.ast.Node.TreeTraversal.PREORDER;
+import static java.util.Collections.unmodifiableList;
+import static java.util.Spliterator.DISTINCT;
+import static java.util.Spliterator.NONNULL;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.metamodel.NodeMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+
+/**
+ * Base class for all nodes of the abstract syntax tree.
+ * <h2>Construction</h2>
+ * <p>The tree is built by instantiating the required nodes, then adding them to other nodes.
+ * If it is the parser who is building the tree, it will use the largest constructor,
+ * the one with "range" as the first parameter.
+ * If you want to manually instantiate nodes, we suggest to...
+ * <ul>
+ * <li>use a convenience method, like "addStatement(...)", or if none are available...</li>
+ * <li>use a convenient constructor, like ClassOrInterfaceType(String name), or if none are available...</li>
+ * <li>use the default constructor.</li>
+ * <li>Alternatively, use one of the JavaParser.parse(snippet) methods.</li>
+ * </ul>
+ * ... and use the various methods on the node to initialize it further, if needed.
+ * <h2>Parent/child</h2>
+ * <p>The parent node field is managed automatically and can be seen as read only.
+ * Note that there is only one parent,
+ * and trying to use the same node in two places will lead to unexpected behaviour.
+ * It is advised to clone() a node before moving it around.
+ * <h2>Comments</h2>
+ * <p>Each Node can have one associated comment which describes it and
+ * a number of "orphan comments" which it contains but are not specifically
+ * associated to any child.
+ * <h2>Positions</h2>
+ * <p>When the parser creates nodes, it sets their source code position in the "range" field.
+ * When you manually instantiate nodes, their range is not set.
+ * The top left character is position 1, 1.
+ * Note that since this is an <i>abstract</i> syntax tree,
+ * it leaves out a lot of text from the original source file,
+ * like where braces or comma's are exactly.
+ * Therefore there is no position information on everything in the original source file.
+ * <h2>Observers</h2>
+ * <p>It is possible to add observers to the the tree.
+ * Any change in the tree is sent as an event to any observers watching.
+ * <h2>Visitors</h2>
+ * <p>The most comfortable way of working with an abstract syntax tree is using visitors.
+ * You can use one of the visitors in the visitor package, or extend one of them.
+ * A visitor can be "run" by calling accept on a node:
+ * <pre>node.accept(visitor, argument);</pre>
+ * where argument is an object of your choice (often simply null.)
+ *
+ * @author Julio Vilmar Gesser
+ */
+public abstract class Node implements Cloneable, HasParentNode<Node>, Visitable, NodeWithRange<Node>, NodeWithTokenRange<Node> {
+
+    /**
+     * Different registration mode for observers on nodes.
+     */
+    public enum ObserverRegistrationMode {
+
+        /**
+         * Notify exclusively for changes happening on this node alone.
+         */
+        JUST_THIS_NODE,
+        /**
+         * Notify for changes happening on this node and all its descendants existing at the moment in
+         * which the observer was registered. Nodes attached later will not be observed.
+         */
+        THIS_NODE_AND_EXISTING_DESCENDANTS,
+        /**
+         * Notify for changes happening on this node and all its descendants. The descendants existing at the moment in
+         * which the observer was registered will be observed immediately. As new nodes are attached later they are
+         * automatically registered to be observed.
+         */
+        SELF_PROPAGATING
+    }
+
+    public enum Parsedness {
+
+        PARSED, UNPARSABLE
+    }
+
+    /**
+     * This can be used to sort nodes on position.
+     */
+    public static Comparator<NodeWithRange<?>> NODE_BY_BEGIN_POSITION = (a, b) -> {
+        if (a.getRange().isPresent() && b.getRange().isPresent()) {
+            return a.getRange().get().begin.compareTo(b.getRange().get().begin);
+        }
+        if (a.getRange().isPresent() || b.getRange().isPresent()) {
+            if (a.getRange().isPresent()) {
+                return 1;
+            }
+            return -1;
+        }
+        return 0;
+    };
+
+    private static final PrettyPrinter toStringPrinter = new PrettyPrinter(new PrettyPrinterConfiguration());
+
+    protected static final PrettyPrinterConfiguration prettyPrinterNoCommentsConfiguration = new PrettyPrinterConfiguration().setPrintComments(false);
+
+    @InternalProperty
+    private Range range;
+
+    @InternalProperty
+    private TokenRange tokenRange;
+
+    @InternalProperty
+    private Node parentNode;
+
+    @InternalProperty
+    private List<Node> childNodes = new LinkedList<>();
+
+    @InternalProperty
+    private List<Comment> orphanComments = new LinkedList<>();
+
+    @InternalProperty
+    private IdentityHashMap<DataKey<?>, Object> data = null;
+
+    @OptionalProperty
+    private Comment comment;
+
+    @InternalProperty
+    private List<AstObserver> observers = new ArrayList<>();
+
+    @InternalProperty
+    private Parsedness parsed = PARSED;
+
+    protected Node(TokenRange tokenRange) {
+        setTokenRange(tokenRange);
+    }
+
+    /**
+     * Called in every constructor for node specific code.
+     * It can't be written in the constructor itself because it will
+     * be overwritten during code generation.
+     */
+    protected void customInitialization() {
+    }
+
+    /**
+     * This is a comment associated with this node.
+     *
+     * @return comment property
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public Optional<Comment> getComment() {
+        return Optional.ofNullable(comment);
+    }
+
+    /**
+     * @return the range of characters in the source code that this node covers.
+     */
+    public Optional<Range> getRange() {
+        return Optional.ofNullable(range);
+    }
+
+    /**
+     * @return the range of tokens that this node covers.
+     */
+    public Optional<TokenRange> getTokenRange() {
+        return Optional.ofNullable(tokenRange);
+    }
+
+    public Node setTokenRange(TokenRange tokenRange) {
+        this.tokenRange = tokenRange;
+        if (tokenRange == null || !(tokenRange.getBegin().getRange().isPresent() && tokenRange.getBegin().getRange().isPresent())) {
+            range = null;
+        } else {
+            range = new Range(tokenRange.getBegin().getRange().get().begin, tokenRange.getEnd().getRange().get().end);
+        }
+        return this;
+    }
+
+    /**
+     * @param range the range of characters in the source code that this node covers. null can be used to indicate that
+     * no range information is known, or that it is not of interest.
+     */
+    public Node setRange(Range range) {
+        if (this.range == range) {
+            return this;
+        }
+        notifyPropertyChange(ObservableProperty.RANGE, this.range, range);
+        this.range = range;
+        return this;
+    }
+
+    /**
+     * Use this to store additional information to this node.
+     *
+     * @param comment to be set
+     */
+    public final Node setComment(final Comment comment) {
+        if (this.comment == comment) {
+            return this;
+        }
+        if (comment != null && (this instanceof Comment)) {
+            throw new RuntimeException("A comment can not be commented");
+        }
+        notifyPropertyChange(ObservableProperty.COMMENT, this.comment, comment);
+        if (this.comment != null) {
+            this.comment.setCommentedNode(null);
+        }
+        this.comment = comment;
+        if (comment != null) {
+            this.comment.setCommentedNode(this);
+        }
+        return this;
+    }
+
+    /**
+     * Use this to store additional information to this node.
+     *
+     * @param comment to be set
+     */
+    public final Node setLineComment(String comment) {
+        return setComment(new LineComment(comment));
+    }
+
+    /**
+     * Use this to store additional information to this node.
+     *
+     * @param comment to be set
+     */
+    public final Node setBlockComment(String comment) {
+        return setComment(new BlockComment(comment));
+    }
+
+    /**
+     * Return the String representation of this node.
+     *
+     * @return the String representation of this node
+     */
+    @Override
+    public final String toString() {
+        return toStringPrinter.print(this);
+    }
+
+    public final String toString(PrettyPrinterConfiguration prettyPrinterConfiguration) {
+        return new PrettyPrinter(prettyPrinterConfiguration).print(this);
+    }
+
+    @Override
+    public final int hashCode() {
+        return HashCodeVisitor.hashCode(this);
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null || !(obj instanceof Node)) {
+            return false;
+        }
+        return EqualsVisitor.equals(this, (Node) obj);
+    }
+
+    @Override
+    public Optional<Node> getParentNode() {
+        return Optional.ofNullable(parentNode);
+    }
+
+    /**
+     * Contains all nodes that have this node set as their parent.
+     * You can add and remove nodes from this list by adding or removing nodes from the fields of this node.
+     *
+     * @return all nodes that have this node as their parent.
+     */
+    public List<Node> getChildNodes() {
+        return unmodifiableList(childNodes);
+    }
+
+    public void addOrphanComment(Comment comment) {
+        orphanComments.add(comment);
+        comment.setParentNode(this);
+    }
+
+    public boolean removeOrphanComment(Comment comment) {
+        boolean removed = orphanComments.remove(comment);
+        if (removed) {
+            comment.setParentNode(null);
+        }
+        return removed;
+    }
+
+    /**
+     * This is a list of Comment which are inside the node and are not associated
+     * with any meaningful AST Node.
+     * <p>
+     * For example, comments at the end of methods (immediately before the parenthesis)
+     * or at the end of CompilationUnit are orphan comments.
+     * <p>
+     * When more than one comment preceeds a statement, the one immediately preceding it
+     * it is associated with the statements, while the others are orphans.
+     * <p>
+     * Changes to this list are not persisted.
+     *
+     * @return all comments that cannot be attributed to a concept
+     */
+    public List<Comment> getOrphanComments() {
+        return new LinkedList<>(orphanComments);
+    }
+
+    /**
+     * This is the list of Comment which are contained in the Node either because
+     * they are properly associated to one of its children or because they are floating
+     * around inside the Node
+     *
+     * @return all Comments within the node as a list
+     */
+    public List<Comment> getAllContainedComments() {
+        List<Comment> comments = new LinkedList<>();
+        comments.addAll(getOrphanComments());
+        for (Node child : getChildNodes()) {
+            child.getComment().ifPresent(comments::add);
+            comments.addAll(child.getAllContainedComments());
+        }
+        return comments;
+    }
+
+    /**
+     * Assign a new parent to this node, removing it
+     * from the list of children of the previous parent, if any.
+     *
+     * @param newParentNode node to be set as parent
+     */
+    @Override
+    public Node setParentNode(Node newParentNode) {
+        if (newParentNode == parentNode) {
+            return this;
+        }
+        observers.forEach(o -> o.parentChange(this, parentNode, newParentNode));
+        // remove from old parent, if any
+        if (parentNode != null) {
+            final List<Node> parentChildNodes = parentNode.childNodes;
+            for (int i = 0; i < parentChildNodes.size(); i++) {
+                if (parentChildNodes.get(i) == this) {
+                    parentChildNodes.remove(i);
+                }
+            }
+        }
+        parentNode = newParentNode;
+        // add to new parent, if any
+        if (parentNode != null) {
+            parentNode.childNodes.add(this);
+        }
+        return this;
+    }
+
+    protected void setAsParentNodeOf(Node childNode) {
+        if (childNode != null) {
+            childNode.setParentNode(getParentNodeForChildren());
+        }
+    }
+
+    public static final int ABSOLUTE_BEGIN_LINE = -1;
+
+    public static final int ABSOLUTE_END_LINE = -2;
+
+    /**
+     * @deprecated use getComment().isPresent()
+     */
+    @Deprecated
+    public boolean hasComment() {
+        return comment != null;
+    }
+
+    public void tryAddImportToParentCompilationUnit(Class<?> clazz) {
+        getAncestorOfType(CompilationUnit.class).ifPresent(p -> p.addImport(clazz));
+    }
+
+    /**
+     * Recursively finds all nodes of a certain type.
+     *
+     * @param clazz the type of node to find.
+     * @deprecated use find(Class)
+     */
+    public <N extends Node> List<N> getChildNodesByType(Class<N> clazz) {
+        List<N> nodes = new ArrayList<>();
+        for (Node child : getChildNodes()) {
+            if (clazz.isInstance(child)) {
+                nodes.add(clazz.cast(child));
+            }
+            nodes.addAll(child.getChildNodesByType(clazz));
+        }
+        return nodes;
+    }
+
+    /**
+     * @deprecated use findAll(Class)
+     */
+    @Deprecated
+    public <N extends Node> List<N> getNodesByType(Class<N> clazz) {
+        return getChildNodesByType(clazz);
+    }
+
+    /**
+     * Gets data for this node using the given key.
+     *
+     * @param <M> The type of the data.
+     * @param key The key for the data
+     * @return The data or null of no data was found for the given key
+     * @see DataKey
+     */
+    @SuppressWarnings("unchecked")
+    public <M> M getData(final DataKey<M> key) {
+        if (data == null) {
+            return null;
+        }
+        return (M) data.get(key);
+    }
+
+    /**
+     * Sets data for this node using the given key.
+     * For information on creating DataKey, see {@link DataKey}.
+     *
+     * @param <M> The type of data
+     * @param key The singleton key for the data
+     * @param object The data object
+     * @see DataKey
+     */
+    public <M> void setData(DataKey<M> key, M object) {
+        if (data == null) {
+            data = new IdentityHashMap<>();
+        }
+        data.put(key, object);
+    }
+
+    /**
+     * @return does this node have data for this key?
+     */
+    public boolean containsData(DataKey<?> key) {
+        if (data == null) {
+            return false;
+        }
+        return data.get(key) != null;
+    }
+
+    /**
+     * Try to remove this node from the parent
+     *
+     * @return true if removed, false if it is a required property of the parent, or if the parent isn't set.
+     * @throws RuntimeException if it fails in an unexpected way
+     */
+    public boolean remove() {
+        if (parentNode == null) {
+            return false;
+        }
+        return parentNode.remove(this);
+    }
+
+    /**
+     * Try to replace this node in the parent with the supplied node.
+     *
+     * @return true if removed, or if the parent isn't set.
+     * @throws RuntimeException if it fails in an unexpected way
+     */
+    public boolean replace(Node node) {
+        if (parentNode == null) {
+            return false;
+        }
+        return parentNode.replace(this, node);
+    }
+
+    /**
+     * Forcibly removes this node from the AST.
+     * If it cannot be removed from the parent with remove(),
+     * it will try to remove its parent instead,
+     * until it finds a node that can be removed,
+     * or no parent can be found.
+     * <p>
+     * Since everything at CompilationUnit level is removable,
+     * this method will only (silently) fail when the node is in a detached AST fragment.
+     */
+    public void removeForced() {
+        if (!remove()) {
+            getParentNode().ifPresent(Node::remove);
+        }
+    }
+
+    @Override
+    public Node getParentNodeForChildren() {
+        return this;
+    }
+
+    protected void setAsParentNodeOf(NodeList<? extends Node> list) {
+        if (list != null) {
+            list.setParentNode(getParentNodeForChildren());
+        }
+    }
+
+    public <P> void notifyPropertyChange(ObservableProperty property, P oldValue, P newValue) {
+        this.observers.forEach(o -> o.propertyChange(this, property, oldValue, newValue));
+    }
+
+    @Override
+    public void unregister(AstObserver observer) {
+        this.observers.remove(observer);
+    }
+
+    @Override
+    public void register(AstObserver observer) {
+        this.observers.add(observer);
+    }
+
+    /**
+     * Register a new observer for the given node. Depending on the mode specified also descendants, existing
+     * and new, could be observed. For more details see <i>ObserverRegistrationMode</i>.
+     */
+    public void register(AstObserver observer, ObserverRegistrationMode mode) {
+        if (mode == null) {
+            throw new IllegalArgumentException("Mode should be not null");
+        }
+        switch(mode) {
+            case JUST_THIS_NODE:
+                register(observer);
+                break;
+            case THIS_NODE_AND_EXISTING_DESCENDANTS:
+                registerForSubtree(observer);
+                break;
+            case SELF_PROPAGATING:
+                registerForSubtree(PropagatingAstObserver.transformInPropagatingObserver(observer));
+                break;
+            default:
+                throw new UnsupportedOperationException("This mode is not supported: " + mode);
+        }
+    }
+
+    /**
+     * Register the observer for the current node and all the contained node and nodelists, recursively.
+     */
+    public void registerForSubtree(AstObserver observer) {
+        register(observer);
+        this.getChildNodes().forEach(c -> c.registerForSubtree(observer));
+        for (PropertyMetaModel property : getMetaModel().getAllPropertyMetaModels()) {
+            if (property.isNodeList()) {
+                NodeList<?> nodeList = (NodeList<?>) property.getValue(this);
+                if (nodeList != null)
+                    nodeList.register(observer);
+            }
+        }
+    }
+
+    @Override
+    public boolean isRegistered(AstObserver observer) {
+        return this.observers.contains(observer);
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public boolean remove(Node node) {
+        if (node == null)
+            return false;
+        if (comment != null) {
+            if (node == comment) {
+                removeComment();
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public Node removeComment() {
+        return setComment((Comment) null);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.CloneGenerator")
+    public Node clone() {
+        return (Node) accept(new CloneVisitor(), null);
+    }
+
+    /**
+     * @return get JavaParser specific node introspection information.
+     */
+    @Generated("com.github.javaparser.generator.core.node.GetMetaModelGenerator")
+    public NodeMetaModel getMetaModel() {
+        return JavaParserMetaModel.nodeMetaModel;
+    }
+
+    /**
+     * @return whether this node was successfully parsed or not.
+     * If it was not, only the range and tokenRange fields will be valid.
+     */
+    public Parsedness getParsed() {
+        return parsed;
+    }
+
+    /**
+     * Used by the parser to flag unparsable nodes.
+     */
+    public Node setParsed(Parsedness parsed) {
+        this.parsed = parsed;
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.ReplaceMethodGenerator")
+    public boolean replace(Node node, Node replacementNode) {
+        if (node == null)
+            return false;
+        if (comment != null) {
+            if (node == comment) {
+                setComment((Comment) replacementNode);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Finds the root node of this AST by finding the topmost parent.
+     */
+    public Node findRootNode() {
+        Node n = this;
+        while (n.getParentNode().isPresent()) {
+            n = n.getParentNode().get();
+        }
+        return n;
+    }
+
+    /**
+     * @return the containing CompilationUnit, or empty if this node is not inside a compilation unit.
+     */
+    public Optional<CompilationUnit> findCompilationUnit() {
+        Node rootNode = findRootNode();
+        if (rootNode instanceof CompilationUnit) {
+            return Optional.of((CompilationUnit) rootNode);
+        }
+        return Optional.empty();
+    }
+
+    protected SymbolResolver getSymbolResolver() {
+        return findCompilationUnit().map(cu -> {
+            SymbolResolver symbolResolver = cu.getData(SYMBOL_RESOLVER_KEY);
+            if (symbolResolver == null) {
+                throw new IllegalStateException("Symbol resolution not configured: to configure consider setting a SymbolResolver in the ParserConfiguration");
+            }
+            return symbolResolver;
+        }).orElseThrow(() -> new IllegalStateException("The node is not inserted in a CompilationUnit"));
+    }
+
+    // We need to expose it because we will need to use it to inject the SymbolSolver
+    public static final DataKey<SymbolResolver> SYMBOL_RESOLVER_KEY = new DataKey<SymbolResolver>() {
+    };
+
+    public enum TreeTraversal {
+
+        PREORDER, BREADTHFIRST, POSTORDER, PARENTS, DIRECT_CHILDREN
+    }
+
+    private Iterator<Node> treeIterator(TreeTraversal traversal) {
+        switch(traversal) {
+            case BREADTHFIRST:
+                return new BreadthFirstIterator(this);
+            case POSTORDER:
+                return new PostOrderIterator(this);
+            case PREORDER:
+                return new PreOrderIterator(this);
+            case DIRECT_CHILDREN:
+                return new DirectChildrenIterator(this);
+            case PARENTS:
+                return new ParentsVisitor(this);
+            default:
+                throw new IllegalArgumentException("Unknown traversal choice.");
+        }
+    }
+
+    private Iterable<Node> treeIterable(TreeTraversal traversal) {
+        return () -> treeIterator(traversal);
+    }
+
+    /**
+     * Make a stream of nodes using traversal algorithm "traversal".
+     */
+    public Stream<Node> stream(TreeTraversal traversal) {
+        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(treeIterator(traversal), NONNULL | DISTINCT), false);
+    }
+
+    /**
+     * Make a stream of nodes using pre-order traversal.
+     */
+    public Stream<Node> stream() {
+        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(treeIterator(PREORDER), NONNULL | DISTINCT), false);
+    }
+
+    /**
+     * Walks the AST, calling the consumer for every node, with traversal algorithm "traversal".
+     * <br/>This is the most general walk method. All other walk and findAll methods are based on this.
+     */
+    public void walk(TreeTraversal traversal, Consumer<Node> consumer) {
+        // Could be implemented as a call to the above walk method, but this is a little more efficient.
+        for (Node node : treeIterable(traversal)) {
+            consumer.accept(node);
+        }
+    }
+
+    /**
+     * Walks the AST, calling the consumer for every node with pre-order traversal.
+     */
+    public void walk(Consumer<Node> consumer) {
+        walk(PREORDER, consumer);
+    }
+
+    /**
+     * Walks the AST with pre-order traversal, calling the consumer for every node of type "nodeType".
+     */
+    public <T extends Node> void walk(Class<T> nodeType, Consumer<T> consumer) {
+        walk(TreeTraversal.PREORDER, node -> {
+            if (nodeType.isAssignableFrom(node.getClass())) {
+                consumer.accept(nodeType.cast(node));
+            }
+        });
+    }
+
+    /**
+     * Walks the AST with pre-order traversal, returning all nodes of type "nodeType".
+     */
+    public <T extends Node> List<T> findAll(Class<T> nodeType) {
+        final List<T> found = new ArrayList<>();
+        walk(nodeType, found::add);
+        return found;
+    }
+
+    /**
+     * Walks the AST with pre-order traversal, returning all nodes of type "nodeType" that match the predicate.
+     */
+    public <T extends Node> List<T> findAll(Class<T> nodeType, Predicate<T> predicate) {
+        final List<T> found = new ArrayList<>();
+        walk(nodeType, n -> {
+            if (predicate.test(n))
+                found.add(n);
+        });
+        return found;
+    }
+
+    /**
+     * Walks the AST, applying the function for every node, with traversal algorithm "traversal". If the function
+     * returns something else than null, the traversal is stopped and the function result is returned. <br/>This is the
+     * most general findFirst method. All other findFirst methods are based on this.
+     */
+    public <T> Optional<T> findFirst(TreeTraversal traversal, Function<Node, Optional<T>> consumer) {
+        for (Node node : treeIterable(traversal)) {
+            final Optional<T> result = consumer.apply(node);
+            if (result.isPresent()) {
+                return result;
+            }
+        }
+        return Optional.empty();
+    }
+
+    /**
+     * Walks the AST with pre-order traversal, returning the first node of type "nodeType" or empty() if none is found.
+     */
+    public <N extends Node> Optional<N> findFirst(Class<N> nodeType) {
+        return findFirst(TreeTraversal.PREORDER, node -> {
+            if (nodeType.isAssignableFrom(node.getClass())) {
+                return Optional.of(nodeType.cast(node));
+            }
+            return Optional.empty();
+        });
+    }
+
+    /**
+     * Walks the AST with pre-order traversal, returning the first node of type "nodeType" that matches "predicate" or empty() if none is
+     * found.
+     */
+    public <N extends Node> Optional<N> findFirst(Class<N> nodeType, Predicate<N> predicate) {
+        return findFirst(TreeTraversal.PREORDER, node -> {
+            if (nodeType.isAssignableFrom(node.getClass())) {
+                final N castNode = nodeType.cast(node);
+                if (predicate.test(castNode)) {
+                    return Optional.of(castNode);
+                }
+            }
+            return Optional.empty();
+        });
+    }
+
+    /**
+     * Walks the parents of this node, returning the first node of type "nodeType" or empty() if none is found.
+     */
+    public <N extends Node> Optional<N> findParent(Class<N> nodeType) {
+        Node n = this;
+        while (n.getParentNode().isPresent()) {
+            n = n.getParentNode().get();
+            if (nodeType.isAssignableFrom(n.getClass())) {
+                return Optional.of(nodeType.cast(n));
+            }
+        }
+        return Optional.empty();
+    }
+
+    /**
+     * Performs a breadth-first node traversal starting with a given node.
+     *
+     * @see <a href="https://en.wikipedia.org/wiki/Breadth-first_search">Breadth-first traversal</a>
+     */
+    public static class BreadthFirstIterator implements Iterator<Node> {
+
+        private final Queue<Node> queue = new LinkedList<>();
+
+        public BreadthFirstIterator(Node node) {
+            queue.add(node);
+        }
+
+        @Override
+        public boolean hasNext() {
+            return !queue.isEmpty();
+        }
+
+        @Override
+        public Node next() {
+            Node next = queue.remove();
+            queue.addAll(next.getChildNodes());
+            return next;
+        }
+    }
+
+    /**
+     * Performs a simple traversal over all nodes that have the passed node as their parent.
+     */
+    public static class DirectChildrenIterator implements Iterator<Node> {
+
+        private final Iterator<Node> childrenIterator;
+
+        public DirectChildrenIterator(Node node) {
+            childrenIterator = new ArrayList<>(node.getChildNodes()).iterator();
+        }
+
+        @Override
+        public boolean hasNext() {
+            return childrenIterator.hasNext();
+        }
+
+        @Override
+        public Node next() {
+            return childrenIterator.next();
+        }
+    }
+
+    /**
+     * Iterates over the parent of the node, then the parent's parent, then the parent's parent's parent, until running
+     * out of parents.
+     */
+    public static class ParentsVisitor implements Iterator<Node> {
+
+        private Node node;
+
+        public ParentsVisitor(Node node) {
+            this.node = node;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return node.getParentNode().isPresent();
+        }
+
+        @Override
+        public Node next() {
+            node = node.getParentNode().orElse(null);
+            return node;
+        }
+    }
+
+    /**
+     * Performs a pre-order (or depth-first) node traversal starting with a given node.
+     *
+     * @see <a href="https://en.wikipedia.org/wiki/Pre-order">Pre-order traversal</a>
+     */
+    public static class PreOrderIterator implements Iterator<Node> {
+
+        private final Stack<Node> stack = new Stack<>();
+
+        public PreOrderIterator(Node node) {
+            stack.add(node);
+        }
+
+        @Override
+        public boolean hasNext() {
+            return !stack.isEmpty();
+        }
+
+        @Override
+        public Node next() {
+            Node next = stack.pop();
+            List<Node> children = next.getChildNodes();
+            for (int i = children.size() - 1; i >= 0; i--) {
+                stack.add(children.get(i));
+            }
+            return next;
+        }
+    }
+
+    /**
+     * Performs a post-order (or leaves-first) node traversal starting with a given node.
+     *
+     * @see <a href="https://en.wikipedia.org/wiki/Post-order">Post-order traversal</a>
+     */
+    public static class PostOrderIterator implements Iterator<Node> {
+
+        private final Stack<List<Node>> nodesStack = new Stack<>();
+
+        private final Stack<Integer> cursorStack = new Stack<>();
+
+        private final Node root;
+
+        private boolean hasNext = true;
+
+        public PostOrderIterator(Node root) {
+            this.root = root;
+            fillStackToLeaf(root);
+        }
+
+        private void fillStackToLeaf(Node node) {
+            while (true) {
+                List<Node> childNodes = new ArrayList<>(node.getChildNodes());
+                if (childNodes.isEmpty()) {
+                    break;
+                }
+                nodesStack.push(childNodes);
+                cursorStack.push(0);
+                node = childNodes.get(0);
+            }
+        }
+
+        @Override
+        public boolean hasNext() {
+            return hasNext;
+        }
+
+        @Override
+        public Node next() {
+            final List<Node> nodes = nodesStack.peek();
+            final int cursor = cursorStack.peek();
+            final boolean levelHasNext = cursor < nodes.size();
+            if (levelHasNext) {
+                Node node = nodes.get(cursor);
+                fillStackToLeaf(node);
+                return nextFromLevel();
+            } else {
+                nodesStack.pop();
+                cursorStack.pop();
+                hasNext = !nodesStack.empty();
+                if (hasNext) {
+                    return nextFromLevel();
+                }
+                return root;
+            }
+        }
+
+        private Node nextFromLevel() {
+            final List<Node> nodes = nodesStack.peek();
+            final int cursor = cursorStack.pop();
+            cursorStack.push(cursor + 1);
+            return nodes.get(cursor);
+        }
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/NodeList.java b/javaparser-core/src/main/java/com/github/javaparser/ast/NodeList.java
new file mode 100644
index 0000000..f370e96
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/NodeList.java
@@ -0,0 +1,542 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser.ast;
+
+import com.github.javaparser.HasParentNode;
+import com.github.javaparser.ast.observer.AstObserver;
+import com.github.javaparser.ast.observer.Observable;
+import com.github.javaparser.ast.visitor.GenericVisitor;
+import com.github.javaparser.ast.visitor.Visitable;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+import com.github.javaparser.metamodel.InternalProperty;
+
+import java.util.*;
+import java.util.function.*;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * A list of nodes.
+ * It usually has a parent node.
+ * Unlike normal Nodes, this does not mean that it is a child of that parent.
+ * Instead, this list will make every node it contains a child of its parent.
+ * This way, a NodeList does not create an extra level inside the AST.
+ *
+ * @param <N> the type of nodes contained.
+ */
+public class NodeList<N extends Node> implements List<N>, Iterable<N>, HasParentNode<NodeList<N>>, Visitable, Observable {
+    @InternalProperty
+    private List<N> innerList = new ArrayList<>(0);
+
+    private Node parentNode;
+
+    private List<AstObserver> observers = new ArrayList<>();
+
+    public NodeList() {
+        parentNode = null;
+    }
+
+    public NodeList(Collection<N> n) {
+        this.addAll(n);
+    }
+
+    public NodeList(N... n) {
+        this.addAll(Arrays.asList(n));
+    }
+
+    @Override
+    public boolean add(N node) {
+        notifyElementAdded(innerList.size(), node);
+        own(node);
+        return innerList.add(node);
+    }
+
+    private void own(N node) {
+        if (node == null) {
+            return;
+        }
+        setAsParentNodeOf(node);
+    }
+
+    public boolean remove(Node node) {
+        int index = innerList.indexOf(node);
+        if (index != -1) {
+            notifyElementRemoved(index, node);
+            node.setParentNode(null);
+        }
+        return innerList.remove(node);
+    }
+
+    public N removeFirst() {
+        return remove(0);
+    }
+
+    public N removeLast() {
+        return remove(innerList.size() - 1);
+    }
+
+    @SafeVarargs
+    public static <X extends Node> NodeList<X> nodeList(X... nodes) {
+        final NodeList<X> nodeList = new NodeList<>();
+        Collections.addAll(nodeList, nodes);
+        return nodeList;
+    }
+
+    public static <X extends Node> NodeList<X> nodeList(Collection<X> nodes) {
+        final NodeList<X> nodeList = new NodeList<>();
+        nodeList.addAll(nodes);
+        return nodeList;
+    }
+
+    public static <X extends Node> NodeList<X> nodeList(NodeList<X> nodes) {
+        final NodeList<X> nodeList = new NodeList<>();
+        nodeList.addAll(nodes);
+        return nodeList;
+    }
+
+    public boolean contains(N node) {
+        return innerList.contains(node);
+    }
+
+    @Override
+    public int size() {
+        return innerList.size();
+    }
+
+    @Override
+    public N get(int i) {
+        return innerList.get(i);
+    }
+
+    @Override
+    public Iterator<N> iterator() {
+        // TODO take care of "Iterator.remove"
+        return innerList.iterator();
+    }
+
+    @Override
+    public N set(int index, N element) {
+        if (index < 0 || index >= innerList.size()) {
+            throw new IllegalArgumentException("Illegal index. The index should be between 0 and " + innerList.size()
+                    + " excluded. It is instead " + index);
+        }
+        if (element == innerList.get(index)) {
+            return element;
+        }
+        notifyElementReplaced(index, element);
+        innerList.get(index).setParentNode(null);
+        setAsParentNodeOf(element);
+        return innerList.set(index, element);
+    }
+
+    @Override
+    public N remove(int index) {
+        notifyElementRemoved(index, innerList.get(index));
+        N remove = innerList.remove(index);
+        if (remove != null)
+            remove.setParentNode(null);
+        return remove;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return innerList.isEmpty();
+    }
+
+    @Override
+    public void sort(Comparator<? super N> comparator) {
+        innerList.sort(comparator);
+    }
+
+    public void addAll(NodeList<N> otherList) {
+        for (N node : otherList) {
+            add(node);
+        }
+    }
+
+    @Override
+    public void add(int index, N node) {
+        notifyElementAdded(index, node);
+        own(node);
+        innerList.add(index, node);
+    }
+
+    /**
+     * Inserts the node before all other nodes.
+     */
+    public NodeList<N> addFirst(N node) {
+        add(0, node);
+        return this;
+    }
+
+    /**
+     * Inserts the node after all other nodes. (This is simply an alias for add.)
+     */
+    public NodeList<N> addLast(N node) {
+        add(node);
+        return this;
+    }
+
+    /**
+     * Inserts the node after afterThisNode.
+     *
+     * @throws IllegalArgumentException when afterThisNode is not in this list.
+     */
+    public NodeList<N> addAfter(N node, N afterThisNode) {
+        int i = indexOf(afterThisNode);
+        if (i == -1) {
+            throw new IllegalArgumentException("Can't find node to insert after.");
+        }
+        add(i + 1, node);
+        return this;
+    }
+
+    /**
+     * Inserts the node before beforeThisNode.
+     *
+     * @throws IllegalArgumentException when beforeThisNode is not in this list.
+     */
+    public NodeList<N> addBefore(N node, N beforeThisNode) {
+        int i = indexOf(beforeThisNode);
+        if (i == -1) {
+            throw new IllegalArgumentException("Can't find node to insert before.");
+        }
+        add(i, node);
+        return this;
+    }
+
+
+    @Override
+    public Optional<Node> getParentNode() {
+        return Optional.ofNullable(parentNode);
+    }
+
+    /**
+     * Sets the parentNode
+     *
+     * @param parentNode the parentNode
+     * @return this, the NodeList
+     */
+    @Override
+    public NodeList<N> setParentNode(Node parentNode) {
+        this.parentNode = parentNode;
+        setAsParentNodeOf(innerList);
+        return this;
+    }
+
+    @Override
+    public Node getParentNodeForChildren() {
+        return parentNode;
+    }
+
+    @Override
+    public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) {
+        return v.visit(this, arg);
+    }
+
+    @Override
+    public <A> void accept(final VoidVisitor<A> v, final A arg) {
+        v.visit(this, arg);
+    }
+
+    /**
+     * @see java.lang.Iterable#forEach(java.util.function.Consumer)
+     */
+    @Override
+    public void forEach(Consumer<? super N> action) {
+        innerList.forEach(action);
+    }
+
+    /**
+     * @see java.util.List#contains(java.lang.Object)
+     */
+    @Override
+    public boolean contains(Object o) {
+        return innerList.contains(o);
+    }
+
+    /**
+     * @see java.util.List#toArray()
+     */
+    @Override
+    public Object[] toArray() {
+        return innerList.toArray();
+    }
+
+    /**
+     * @see java.util.List#toArray(java.lang.Object[])
+     */
+    @Override
+    public <T> T[] toArray(T[] a) {
+        return innerList.toArray(a);
+    }
+
+    /**
+     * @see java.util.List#remove(java.lang.Object)
+     */
+    @Override
+    public boolean remove(Object o) {
+        if (o instanceof Node) {
+            return remove((Node) o);
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * @see java.util.List#containsAll(java.util.Collection)
+     */
+    @Override
+    public boolean containsAll(Collection<?> c) {
+        return innerList.containsAll(c);
+    }
+
+    /**
+     * @see java.util.List#addAll(java.util.Collection)
+     */
+    @Override
+    public boolean addAll(Collection<? extends N> c) {
+        c.forEach(this::add);
+        return !c.isEmpty();
+    }
+
+    /**
+     * @see java.util.List#addAll(int, java.util.Collection)
+     */
+    @Override
+    public boolean addAll(int index, Collection<? extends N> c) {
+        for (N e : c) {
+            add(index++, e);
+        }
+        return !c.isEmpty();
+    }
+
+    /**
+     * @see java.util.List#removeAll(java.util.Collection)
+     */
+    @Override
+    public boolean removeAll(Collection<?> c) {
+        boolean changed = false;
+        for (Object e : c) {
+            changed = remove(e) || changed;
+        }
+        return changed;
+    }
+
+    /**
+     * @see java.util.List#retainAll(java.util.Collection)
+     */
+    @Override
+    public boolean retainAll(Collection<?> c) {
+        boolean changed = false;
+        for (Object e : this.stream().filter(it -> !c.contains(it)).toArray()) {
+            if (!c.contains(e)) {
+                changed = remove(e) || changed;
+            }
+        }
+        return changed;
+    }
+
+    /**
+     * @see java.util.List#replaceAll(java.util.function.UnaryOperator)
+     */
+    @Override
+    public void replaceAll(UnaryOperator<N> operator) {
+        for (int i = 0; i < this.size(); i++) {
+            set(i, operator.apply(this.get(i)));
+        }
+    }
+
+    /**
+     * @see java.util.Collection#removeIf(java.util.function.Predicate)
+     */
+    @Override
+    public boolean removeIf(Predicate<? super N> filter) {
+        boolean changed = false;
+        for (Object e : this.stream().filter(filter).toArray()) {
+            changed = remove(e) || changed;
+        }
+        return changed;
+    }
+
+    /**
+     * @see java.util.List#clear()
+     */
+    @Override
+    public void clear() {
+        while (!isEmpty()) {
+            remove(0);
+        }
+    }
+
+    /**
+     * @see java.util.List#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object o) {
+        return innerList.equals(o);
+    }
+
+    /**
+     * @see java.util.List#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return innerList.hashCode();
+    }
+
+    /**
+     * @see java.util.List#indexOf(java.lang.Object)
+     */
+    @Override
+    public int indexOf(Object o) {
+        return innerList.indexOf(o);
+    }
+
+    /**
+     * @see java.util.List#lastIndexOf(java.lang.Object)
+     */
+    @Override
+    public int lastIndexOf(Object o) {
+        return innerList.lastIndexOf(o);
+    }
+
+    /**
+     * @see java.util.List#listIterator()
+     */
+    @Override
+    public ListIterator<N> listIterator() {
+        return innerList.listIterator();
+    }
+
+    /**
+     * @see java.util.List#listIterator(int)
+     */
+    @Override
+    public ListIterator<N> listIterator(int index) {
+        return innerList.listIterator(index);
+    }
+
+    /**
+     * @see java.util.Collection#parallelStream()
+     */
+    @Override
+    public Stream<N> parallelStream() {
+        return innerList.parallelStream();
+    }
+
+    /**
+     * @see java.util.List#subList(int, int)
+     */
+    @Override
+    public List<N> subList(int fromIndex, int toIndex) {
+        return innerList.subList(fromIndex, toIndex);
+    }
+
+    /**
+     * @see java.util.List#spliterator()
+     */
+    @Override
+    public Spliterator<N> spliterator() {
+        return innerList.spliterator();
+    }
+
+    private void notifyElementAdded(int index, Node nodeAddedOrRemoved) {
+        this.observers.forEach(o -> o.listChange(this, AstObserver.ListChangeType.ADDITION, index, nodeAddedOrRemoved));
+    }
+
+    private void notifyElementRemoved(int index, Node nodeAddedOrRemoved) {
+        this.observers.forEach(o -> o.listChange(this, AstObserver.ListChangeType.REMOVAL, index, nodeAddedOrRemoved));
+    }
+
+    private void notifyElementReplaced(int index, Node nodeAddedOrRemoved) {
+        this.observers.forEach(o -> o.listReplacement(this, index, this.get(index), nodeAddedOrRemoved));
+    }
+
+    @Override
+    public void unregister(AstObserver observer) {
+        this.observers.remove(observer);
+    }
+
+    @Override
+    public void register(AstObserver observer) {
+        this.observers.add(observer);
+    }
+
+    @Override
+    public boolean isRegistered(AstObserver observer) {
+        return this.observers.contains(observer);
+    }
+
+    /**
+     * Replaces the first node that is equal to "old" with "replacement".
+     *
+     * @return true if a replacement has happened.
+     */
+    public boolean replace(N old, N replacement) {
+        int i = indexOf(old);
+        if (i == -1) {
+            return false;
+        }
+        set(i, replacement);
+        return true;
+    }
+
+    /**
+     * @return the opposite of isEmpty()
+     */
+    public boolean isNonEmpty() {
+        return !isEmpty();
+    }
+
+    public void ifNonEmpty(Consumer<? super NodeList<N>> consumer) {
+        if (isNonEmpty())
+            consumer.accept(this);
+    }
+
+    public static <T extends Node> Collector<T, NodeList<T>, NodeList<T>> toNodeList() {
+        return Collector.of(NodeList::new, NodeList::add, (left, right) -> {
+            left.addAll(right);
+            return left;
+        });
+    }
+
+    private void setAsParentNodeOf(List<? extends Node> childNodes) {
+        if (childNodes != null) {
+            for (HasParentNode current : childNodes) {
+                current.setParentNode(getParentNodeForChildren());
+            }
+        }
+    }
+
+    private void setAsParentNodeOf(Node childNode) {
+        if (childNode != null) {
+            childNode.setParentNode(getParentNodeForChildren());
+        }
+    }
+
+    @Override
+    public String toString() {
+        return innerList.stream().map(Node::toString).collect(Collectors.joining(", ", "[", "]"));
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/PackageDeclaration.java b/javaparser-core/src/main/java/com/github/javaparser/ast/PackageDeclaration.java
new file mode 100644
index 0000000..65a1ca7
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/PackageDeclaration.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.ast;
+
+import com.github.javaparser.ast.expr.AnnotationExpr;
+import com.github.javaparser.ast.expr.Name;
+import com.github.javaparser.ast.nodeTypes.NodeWithAnnotations;
+import com.github.javaparser.ast.nodeTypes.NodeWithName;
+import com.github.javaparser.ast.observer.ObservableProperty;
+import com.github.javaparser.ast.visitor.GenericVisitor;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+import java.util.Arrays;
+import java.util.List;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.visitor.CloneVisitor;
+import com.github.javaparser.metamodel.PackageDeclarationMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import javax.annotation.Generated;
+import com.github.javaparser.TokenRange;
+
+/**
+ * A package declaration.
+ * <br/><code>package com.github.javaparser.ast;</code>
+ * <br/><code>@Wonderful package anything.can.be.annotated.nowadays;</code>
+ *
+ * @author Julio Vilmar Gesser
+ */
+public final class PackageDeclaration extends Node implements NodeWithAnnotations<PackageDeclaration>, NodeWithName<PackageDeclaration> {
+
+    private NodeList<AnnotationExpr> annotations = new NodeList<>();
+
+    private Name name;
+
+    public PackageDeclaration() {
+        this(null, new NodeList<>(), new Name());
+    }
+
+    public PackageDeclaration(Name name) {
+        this(null, new NodeList<>(), name);
+    }
+
+    @AllFieldsConstructor
+    public PackageDeclaration(NodeList<AnnotationExpr> annotations, Name name) {
+        this(null, annotations, name);
+    }
+
+    /**
+     * This constructor is used by the parser and is considered private.
+     */
+    @Generated("com.github.javaparser.generator.core.node.MainConstructorGenerator")
+    public PackageDeclaration(TokenRange tokenRange, NodeList<AnnotationExpr> annotations, Name name) {
+        super(tokenRange);
+        setAnnotations(annotations);
+        setName(name);
+        customInitialization();
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) {
+        return v.visit(this, arg);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <A> void accept(final VoidVisitor<A> v, final A arg) {
+        v.visit(this, arg);
+    }
+
+    /**
+     * Retrieves the list of annotations declared before the package
+     * declaration. Return <code>null</code> if there are no annotations.
+     *
+     * @return list of annotations or <code>null</code>
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public NodeList<AnnotationExpr> getAnnotations() {
+        return annotations;
+    }
+
+    /**
+     * Return the name expression of the package.
+     *
+     * @return the name of the package
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public Name getName() {
+        return name;
+    }
+
+    /**
+     * @param annotations the annotations to set
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public PackageDeclaration setAnnotations(final NodeList<AnnotationExpr> annotations) {
+        assertNotNull(annotations);
+        if (annotations == this.annotations) {
+            return (PackageDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.ANNOTATIONS, this.annotations, annotations);
+        if (this.annotations != null)
+            this.annotations.setParentNode(null);
+        this.annotations = annotations;
+        setAsParentNodeOf(annotations);
+        return this;
+    }
+
+    /**
+     * Sets the name of this package declaration.
+     *
+     * @param name the name to set
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public PackageDeclaration setName(final Name name) {
+        assertNotNull(name);
+        if (name == this.name) {
+            return (PackageDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.NAME, this.name, name);
+        if (this.name != null)
+            this.name.setParentNode(null);
+        this.name = name;
+        setAsParentNodeOf(name);
+        return this;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public boolean remove(Node node) {
+        if (node == null)
+            return false;
+        for (int i = 0; i < annotations.size(); i++) {
+            if (annotations.get(i) == node) {
+                annotations.remove(i);
+                return true;
+            }
+        }
+        return super.remove(node);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.CloneGenerator")
+    public PackageDeclaration clone() {
+        return (PackageDeclaration) accept(new CloneVisitor(), null);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.GetMetaModelGenerator")
+    public PackageDeclarationMetaModel getMetaModel() {
+        return JavaParserMetaModel.packageDeclarationMetaModel;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.ReplaceMethodGenerator")
+    public boolean replace(Node node, Node replacementNode) {
+        if (node == null)
+            return false;
+        for (int i = 0; i < annotations.size(); i++) {
+            if (annotations.get(i) == node) {
+                annotations.set(i, (AnnotationExpr) replacementNode);
+                return true;
+            }
+        }
+        if (node == name) {
+            setName((Name) replacementNode);
+            return true;
+        }
+        return super.replace(node, replacementNode);
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/body/AnnotationDeclaration.java b/javaparser-core/src/main/java/com/github/javaparser/ast/body/AnnotationDeclaration.java
new file mode 100644
index 0000000..aa793ef
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/body/AnnotationDeclaration.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.ast.body;
+
+import com.github.javaparser.ast.AllFieldsConstructor;
+import com.github.javaparser.ast.Modifier;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.expr.AnnotationExpr;
+import com.github.javaparser.ast.expr.SimpleName;
+import com.github.javaparser.ast.nodeTypes.modifiers.NodeWithAbstractModifier;
+import com.github.javaparser.ast.visitor.CloneVisitor;
+import com.github.javaparser.ast.visitor.GenericVisitor;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+import com.github.javaparser.metamodel.AnnotationDeclarationMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.List;
+import javax.annotation.Generated;
+import com.github.javaparser.TokenRange;
+import com.github.javaparser.resolution.Resolvable;
+import com.github.javaparser.resolution.declarations.ResolvedAnnotationDeclaration;
+import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration;
+import java.util.function.Consumer;
+import java.util.Optional;
+
+/**
+ * An annotation type declaration.<br/><code>@interface X { ... }</code>
+ *
+ * @author Julio Vilmar Gesser
+ */
+public final class AnnotationDeclaration extends TypeDeclaration<AnnotationDeclaration> implements NodeWithAbstractModifier<AnnotationDeclaration>, Resolvable<ResolvedAnnotationDeclaration> {
+
+    public AnnotationDeclaration() {
+        this(null, EnumSet.noneOf(Modifier.class), new NodeList<>(), new SimpleName(), new NodeList<>());
+    }
+
+    public AnnotationDeclaration(EnumSet<Modifier> modifiers, String name) {
+        this(null, modifiers, new NodeList<>(), new SimpleName(name), new NodeList<>());
+    }
+
+    @AllFieldsConstructor
+    public AnnotationDeclaration(EnumSet<Modifier> modifiers, NodeList<AnnotationExpr> annotations, SimpleName name, NodeList<BodyDeclaration<?>> members) {
+        this(null, modifiers, annotations, name, members);
+    }
+
+    /**
+     * This constructor is used by the parser and is considered private.
+     */
+    @Generated("com.github.javaparser.generator.core.node.MainConstructorGenerator")
+    public AnnotationDeclaration(TokenRange tokenRange, EnumSet<Modifier> modifiers, NodeList<AnnotationExpr> annotations, SimpleName name, NodeList<BodyDeclaration<?>> members) {
+        super(tokenRange, modifiers, annotations, name, members);
+        customInitialization();
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) {
+        return v.visit(this, arg);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <A> void accept(final VoidVisitor<A> v, final A arg) {
+        v.visit(this, arg);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public boolean remove(Node node) {
+        if (node == null)
+            return false;
+        return super.remove(node);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.CloneGenerator")
+    public AnnotationDeclaration clone() {
+        return (AnnotationDeclaration) accept(new CloneVisitor(), null);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.GetMetaModelGenerator")
+    public AnnotationDeclarationMetaModel getMetaModel() {
+        return JavaParserMetaModel.annotationDeclarationMetaModel;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.ReplaceMethodGenerator")
+    public boolean replace(Node node, Node replacementNode) {
+        if (node == null)
+            return false;
+        return super.replace(node, replacementNode);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isAnnotationDeclaration() {
+        return true;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public AnnotationDeclaration asAnnotationDeclaration() {
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifAnnotationDeclaration(Consumer<AnnotationDeclaration> action) {
+        action.accept(this);
+    }
+
+    @Override
+    public ResolvedAnnotationDeclaration resolve() {
+        return getSymbolResolver().resolveDeclaration(this, ResolvedAnnotationDeclaration.class);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<AnnotationDeclaration> toAnnotationDeclaration() {
+        return Optional.of(this);
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/body/AnnotationMemberDeclaration.java b/javaparser-core/src/main/java/com/github/javaparser/ast/body/AnnotationMemberDeclaration.java
new file mode 100644
index 0000000..48b6db6
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/body/AnnotationMemberDeclaration.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.ast.body;
+
+import com.github.javaparser.TokenRange;
+import com.github.javaparser.ast.AllFieldsConstructor;
+import com.github.javaparser.ast.Modifier;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.expr.AnnotationExpr;
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.expr.SimpleName;
+import com.github.javaparser.ast.nodeTypes.NodeWithJavadoc;
+import com.github.javaparser.ast.nodeTypes.NodeWithSimpleName;
+import com.github.javaparser.ast.nodeTypes.NodeWithType;
+import com.github.javaparser.ast.nodeTypes.modifiers.NodeWithAbstractModifier;
+import com.github.javaparser.ast.nodeTypes.modifiers.NodeWithPublicModifier;
+import com.github.javaparser.ast.observer.ObservableProperty;
+import com.github.javaparser.ast.type.ClassOrInterfaceType;
+import com.github.javaparser.ast.type.Type;
+import com.github.javaparser.ast.visitor.CloneVisitor;
+import com.github.javaparser.ast.visitor.GenericVisitor;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+import com.github.javaparser.metamodel.AnnotationMemberDeclarationMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import com.github.javaparser.metamodel.OptionalProperty;
+import com.github.javaparser.resolution.Resolvable;
+import com.github.javaparser.resolution.declarations.ResolvedAnnotationMemberDeclaration;
+import com.github.javaparser.resolution.declarations.ResolvedConstructorDeclaration;
+import javax.annotation.Generated;
+import java.util.EnumSet;
+import java.util.Optional;
+import java.util.function.Consumer;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+
+/**
+ * The "int id();" in <code>@interface X { int id(); }</code>
+ * <p>
+ * <br/>All annotations preceding the type will be set on this object, not on the type. JavaParser doesn't know if it
+ * they are applicable to the method or the type.
+ *
+ * @author Julio Vilmar Gesser
+ */
+public final class AnnotationMemberDeclaration extends BodyDeclaration<AnnotationMemberDeclaration> implements NodeWithJavadoc<AnnotationMemberDeclaration>, NodeWithSimpleName<AnnotationMemberDeclaration>, NodeWithType<AnnotationMemberDeclaration, Type>, NodeWithPublicModifier<AnnotationMemberDeclaration>, NodeWithAbstractModifier<AnnotationMemberDeclaration>, Resolvable<ResolvedAnnotationMemberDeclaration> {
+
+    private EnumSet<Modifier> modifiers;
+
+    private Type type;
+
+    private SimpleName name;
+
+    @OptionalProperty
+    private Expression defaultValue;
+
+    public AnnotationMemberDeclaration() {
+        this(null, EnumSet.noneOf(Modifier.class), new NodeList<>(), new ClassOrInterfaceType(), new SimpleName(), null);
+    }
+
+    public AnnotationMemberDeclaration(EnumSet<Modifier> modifiers, Type type, String name, Expression defaultValue) {
+        this(null, modifiers, new NodeList<>(), type, new SimpleName(name), defaultValue);
+    }
+
+    @AllFieldsConstructor
+    public AnnotationMemberDeclaration(EnumSet<Modifier> modifiers, NodeList<AnnotationExpr> annotations, Type type, SimpleName name, Expression defaultValue) {
+        this(null, modifiers, annotations, type, name, defaultValue);
+    }
+
+    /**
+     * This constructor is used by the parser and is considered private.
+     */
+    @Generated("com.github.javaparser.generator.core.node.MainConstructorGenerator")
+    public AnnotationMemberDeclaration(TokenRange tokenRange, EnumSet<Modifier> modifiers, NodeList<AnnotationExpr> annotations, Type type, SimpleName name, Expression defaultValue) {
+        super(tokenRange, annotations);
+        setModifiers(modifiers);
+        setType(type);
+        setName(name);
+        setDefaultValue(defaultValue);
+        customInitialization();
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) {
+        return v.visit(this, arg);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <A> void accept(final VoidVisitor<A> v, final A arg) {
+        v.visit(this, arg);
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public Optional<Expression> getDefaultValue() {
+        return Optional.ofNullable(defaultValue);
+    }
+
+    /**
+     * Return the modifiers of this member declaration.
+     *
+     * @return modifiers
+     * @see Modifier
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public EnumSet<Modifier> getModifiers() {
+        return modifiers;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public SimpleName getName() {
+        return name;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public Type getType() {
+        return type;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public AnnotationMemberDeclaration removeDefaultValue() {
+        return setDefaultValue((Expression) null);
+    }
+
+    /**
+     * Sets the default value
+     *
+     * @param defaultValue the default value, can be null
+     * @return this, the AnnotationMemberDeclaration
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public AnnotationMemberDeclaration setDefaultValue(final Expression defaultValue) {
+        if (defaultValue == this.defaultValue) {
+            return (AnnotationMemberDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.DEFAULT_VALUE, this.defaultValue, defaultValue);
+        if (this.defaultValue != null)
+            this.defaultValue.setParentNode(null);
+        this.defaultValue = defaultValue;
+        setAsParentNodeOf(defaultValue);
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public AnnotationMemberDeclaration setModifiers(final EnumSet<Modifier> modifiers) {
+        assertNotNull(modifiers);
+        if (modifiers == this.modifiers) {
+            return (AnnotationMemberDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.MODIFIERS, this.modifiers, modifiers);
+        this.modifiers = modifiers;
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public AnnotationMemberDeclaration setName(final SimpleName name) {
+        assertNotNull(name);
+        if (name == this.name) {
+            return (AnnotationMemberDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.NAME, this.name, name);
+        if (this.name != null)
+            this.name.setParentNode(null);
+        this.name = name;
+        setAsParentNodeOf(name);
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public AnnotationMemberDeclaration setType(final Type type) {
+        assertNotNull(type);
+        if (type == this.type) {
+            return (AnnotationMemberDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.TYPE, this.type, type);
+        if (this.type != null)
+            this.type.setParentNode(null);
+        this.type = type;
+        setAsParentNodeOf(type);
+        return this;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public boolean remove(Node node) {
+        if (node == null)
+            return false;
+        if (defaultValue != null) {
+            if (node == defaultValue) {
+                removeDefaultValue();
+                return true;
+            }
+        }
+        return super.remove(node);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.CloneGenerator")
+    public AnnotationMemberDeclaration clone() {
+        return (AnnotationMemberDeclaration) accept(new CloneVisitor(), null);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.GetMetaModelGenerator")
+    public AnnotationMemberDeclarationMetaModel getMetaModel() {
+        return JavaParserMetaModel.annotationMemberDeclarationMetaModel;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.ReplaceMethodGenerator")
+    public boolean replace(Node node, Node replacementNode) {
+        if (node == null)
+            return false;
+        if (defaultValue != null) {
+            if (node == defaultValue) {
+                setDefaultValue((Expression) replacementNode);
+                return true;
+            }
+        }
+        if (node == name) {
+            setName((SimpleName) replacementNode);
+            return true;
+        }
+        if (node == type) {
+            setType((Type) replacementNode);
+            return true;
+        }
+        return super.replace(node, replacementNode);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isAnnotationMemberDeclaration() {
+        return true;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public AnnotationMemberDeclaration asAnnotationMemberDeclaration() {
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifAnnotationMemberDeclaration(Consumer<AnnotationMemberDeclaration> action) {
+        action.accept(this);
+    }
+
+    @Override
+    public ResolvedAnnotationMemberDeclaration resolve() {
+        return getSymbolResolver().resolveDeclaration(this, ResolvedAnnotationMemberDeclaration.class);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<AnnotationMemberDeclaration> toAnnotationMemberDeclaration() {
+        return Optional.of(this);
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/body/BodyDeclaration.java b/javaparser-core/src/main/java/com/github/javaparser/ast/body/BodyDeclaration.java
new file mode 100644
index 0000000..dc871e3
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/body/BodyDeclaration.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.ast.body;
+
+import com.github.javaparser.ast.AllFieldsConstructor;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.expr.AnnotationExpr;
+import com.github.javaparser.ast.nodeTypes.NodeWithAnnotations;
+import com.github.javaparser.ast.observer.ObservableProperty;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+import com.github.javaparser.ast.visitor.CloneVisitor;
+import com.github.javaparser.metamodel.BodyDeclarationMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import javax.annotation.Generated;
+import com.github.javaparser.TokenRange;
+import java.util.function.Consumer;
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+import java.util.Optional;
+
+/**
+ * Any declaration that can appear between the { and } of a class, interface, or enum.
+ *
+ * @author Julio Vilmar Gesser
+ */
+public abstract class BodyDeclaration<T extends BodyDeclaration<?>> extends Node implements NodeWithAnnotations<T> {
+
+    private NodeList<AnnotationExpr> annotations;
+
+    public BodyDeclaration() {
+        this(null, new NodeList<>());
+    }
+
+    @AllFieldsConstructor
+    public BodyDeclaration(NodeList<AnnotationExpr> annotations) {
+        this(null, annotations);
+    }
+
+    /**
+     * This constructor is used by the parser and is considered private.
+     */
+    @Generated("com.github.javaparser.generator.core.node.MainConstructorGenerator")
+    public BodyDeclaration(TokenRange tokenRange, NodeList<AnnotationExpr> annotations) {
+        super(tokenRange);
+        setAnnotations(annotations);
+        customInitialization();
+    }
+
+    protected BodyDeclaration(TokenRange range) {
+        this(range, new NodeList<>());
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public NodeList<AnnotationExpr> getAnnotations() {
+        return annotations;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    @SuppressWarnings("unchecked")
+    public T setAnnotations(final NodeList<AnnotationExpr> annotations) {
+        assertNotNull(annotations);
+        if (annotations == this.annotations) {
+            return (T) this;
+        }
+        notifyPropertyChange(ObservableProperty.ANNOTATIONS, this.annotations, annotations);
+        if (this.annotations != null)
+            this.annotations.setParentNode(null);
+        this.annotations = annotations;
+        setAsParentNodeOf(annotations);
+        return (T) this;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public boolean remove(Node node) {
+        if (node == null)
+            return false;
+        for (int i = 0; i < annotations.size(); i++) {
+            if (annotations.get(i) == node) {
+                annotations.remove(i);
+                return true;
+            }
+        }
+        return super.remove(node);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.CloneGenerator")
+    public BodyDeclaration<?> clone() {
+        return (BodyDeclaration<?>) accept(new CloneVisitor(), null);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.GetMetaModelGenerator")
+    public BodyDeclarationMetaModel getMetaModel() {
+        return JavaParserMetaModel.bodyDeclarationMetaModel;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.ReplaceMethodGenerator")
+    public boolean replace(Node node, Node replacementNode) {
+        if (node == null)
+            return false;
+        for (int i = 0; i < annotations.size(); i++) {
+            if (annotations.get(i) == node) {
+                annotations.set(i, (AnnotationExpr) replacementNode);
+                return true;
+            }
+        }
+        return super.replace(node, replacementNode);
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isAnnotationDeclaration() {
+        return false;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public AnnotationDeclaration asAnnotationDeclaration() {
+        throw new IllegalStateException(f("%s is not an AnnotationDeclaration", this));
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isAnnotationMemberDeclaration() {
+        return false;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public AnnotationMemberDeclaration asAnnotationMemberDeclaration() {
+        throw new IllegalStateException(f("%s is not an AnnotationMemberDeclaration", this));
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isCallableDeclaration() {
+        return false;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public CallableDeclaration asCallableDeclaration() {
+        throw new IllegalStateException(f("%s is not an CallableDeclaration", this));
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isClassOrInterfaceDeclaration() {
+        return false;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public ClassOrInterfaceDeclaration asClassOrInterfaceDeclaration() {
+        throw new IllegalStateException(f("%s is not an ClassOrInterfaceDeclaration", this));
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isConstructorDeclaration() {
+        return false;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public ConstructorDeclaration asConstructorDeclaration() {
+        throw new IllegalStateException(f("%s is not an ConstructorDeclaration", this));
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isEnumConstantDeclaration() {
+        return false;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public EnumConstantDeclaration asEnumConstantDeclaration() {
+        throw new IllegalStateException(f("%s is not an EnumConstantDeclaration", this));
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isEnumDeclaration() {
+        return false;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public EnumDeclaration asEnumDeclaration() {
+        throw new IllegalStateException(f("%s is not an EnumDeclaration", this));
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isFieldDeclaration() {
+        return false;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public FieldDeclaration asFieldDeclaration() {
+        throw new IllegalStateException(f("%s is not an FieldDeclaration", this));
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isInitializerDeclaration() {
+        return false;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public InitializerDeclaration asInitializerDeclaration() {
+        throw new IllegalStateException(f("%s is not an InitializerDeclaration", this));
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isMethodDeclaration() {
+        return false;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public MethodDeclaration asMethodDeclaration() {
+        throw new IllegalStateException(f("%s is not an MethodDeclaration", this));
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isTypeDeclaration() {
+        return false;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public TypeDeclaration asTypeDeclaration() {
+        throw new IllegalStateException(f("%s is not an TypeDeclaration", this));
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifAnnotationDeclaration(Consumer<AnnotationDeclaration> action) {
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifAnnotationMemberDeclaration(Consumer<AnnotationMemberDeclaration> action) {
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifCallableDeclaration(Consumer<CallableDeclaration> action) {
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifClassOrInterfaceDeclaration(Consumer<ClassOrInterfaceDeclaration> action) {
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifConstructorDeclaration(Consumer<ConstructorDeclaration> action) {
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifEnumConstantDeclaration(Consumer<EnumConstantDeclaration> action) {
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifEnumDeclaration(Consumer<EnumDeclaration> action) {
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifFieldDeclaration(Consumer<FieldDeclaration> action) {
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifInitializerDeclaration(Consumer<InitializerDeclaration> action) {
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifMethodDeclaration(Consumer<MethodDeclaration> action) {
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifTypeDeclaration(Consumer<TypeDeclaration> action) {
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<AnnotationDeclaration> toAnnotationDeclaration() {
+        return Optional.empty();
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<AnnotationMemberDeclaration> toAnnotationMemberDeclaration() {
+        return Optional.empty();
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<CallableDeclaration> toCallableDeclaration() {
+        return Optional.empty();
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<ClassOrInterfaceDeclaration> toClassOrInterfaceDeclaration() {
+        return Optional.empty();
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<ConstructorDeclaration> toConstructorDeclaration() {
+        return Optional.empty();
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<EnumConstantDeclaration> toEnumConstantDeclaration() {
+        return Optional.empty();
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<EnumDeclaration> toEnumDeclaration() {
+        return Optional.empty();
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<FieldDeclaration> toFieldDeclaration() {
+        return Optional.empty();
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<InitializerDeclaration> toInitializerDeclaration() {
+        return Optional.empty();
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<MethodDeclaration> toMethodDeclaration() {
+        return Optional.empty();
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<TypeDeclaration> toTypeDeclaration() {
+        return Optional.empty();
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/body/CallableDeclaration.java b/javaparser-core/src/main/java/com/github/javaparser/ast/body/CallableDeclaration.java
new file mode 100644
index 0000000..e2e41fe
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/body/CallableDeclaration.java
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2017 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.ast.body;
+
+import com.github.javaparser.TokenRange;
+import com.github.javaparser.ast.AllFieldsConstructor;
+import com.github.javaparser.ast.Modifier;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.expr.AnnotationExpr;
+import com.github.javaparser.ast.expr.SimpleName;
+import com.github.javaparser.ast.nodeTypes.*;
+import com.github.javaparser.ast.nodeTypes.modifiers.*;
+import com.github.javaparser.ast.observer.ObservableProperty;
+import com.github.javaparser.ast.type.ArrayType;
+import com.github.javaparser.ast.type.ReferenceType;
+import com.github.javaparser.ast.type.Type;
+import com.github.javaparser.ast.type.TypeParameter;
+import com.github.javaparser.ast.visitor.CloneVisitor;
+import com.github.javaparser.metamodel.CallableDeclarationMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import com.github.javaparser.metamodel.OptionalProperty;
+import javax.annotation.Generated;
+import java.util.EnumSet;
+import java.util.List;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toList;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+/**
+ * Represents a declaration which is callable eg. a method or a constructor.
+ */
+public abstract class CallableDeclaration<T extends CallableDeclaration<?>> extends BodyDeclaration<T> implements NodeWithAccessModifiers<T>, NodeWithDeclaration, NodeWithSimpleName<T>, NodeWithParameters<T>, NodeWithThrownExceptions<T>, NodeWithTypeParameters<T>, NodeWithJavadoc<T>, NodeWithAbstractModifier<T>, NodeWithStaticModifier<T>, NodeWithFinalModifier<T>, NodeWithStrictfpModifier<T> {
+
+    private EnumSet<Modifier> modifiers;
+
+    private NodeList<TypeParameter> typeParameters;
+
+    private SimpleName name;
+
+    private NodeList<Parameter> parameters;
+
+    private NodeList<ReferenceType> thrownExceptions;
+
+    @OptionalProperty
+    private ReceiverParameter receiverParameter;
+
+    @AllFieldsConstructor
+    CallableDeclaration(EnumSet<Modifier> modifiers, NodeList<AnnotationExpr> annotations, NodeList<TypeParameter> typeParameters, SimpleName name, NodeList<Parameter> parameters, NodeList<ReferenceType> thrownExceptions, ReceiverParameter receiverParameter) {
+        this(null, modifiers, annotations, typeParameters, name, parameters, thrownExceptions, receiverParameter);
+    }
+
+    /**
+     * This constructor is used by the parser and is considered private.
+     */
+    @Generated("com.github.javaparser.generator.core.node.MainConstructorGenerator")
+    public CallableDeclaration(TokenRange tokenRange, EnumSet<Modifier> modifiers, NodeList<AnnotationExpr> annotations, NodeList<TypeParameter> typeParameters, SimpleName name, NodeList<Parameter> parameters, NodeList<ReferenceType> thrownExceptions, ReceiverParameter receiverParameter) {
+        super(tokenRange, annotations);
+        setModifiers(modifiers);
+        setTypeParameters(typeParameters);
+        setName(name);
+        setParameters(parameters);
+        setThrownExceptions(thrownExceptions);
+        setReceiverParameter(receiverParameter);
+        customInitialization();
+    }
+
+    /**
+     * Return the modifiers of this member declaration.
+     *
+     * @return modifiers
+     * @see Modifier
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public EnumSet<Modifier> getModifiers() {
+        return modifiers;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    @SuppressWarnings("unchecked")
+    public T setModifiers(final EnumSet<Modifier> modifiers) {
+        assertNotNull(modifiers);
+        if (modifiers == this.modifiers) {
+            return (T) this;
+        }
+        notifyPropertyChange(ObservableProperty.MODIFIERS, this.modifiers, modifiers);
+        this.modifiers = modifiers;
+        return (T) this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public SimpleName getName() {
+        return name;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    @SuppressWarnings("unchecked")
+    public T setName(final SimpleName name) {
+        assertNotNull(name);
+        if (name == this.name) {
+            return (T) this;
+        }
+        notifyPropertyChange(ObservableProperty.NAME, this.name, name);
+        if (this.name != null)
+            this.name.setParentNode(null);
+        this.name = name;
+        setAsParentNodeOf(name);
+        return (T) this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public NodeList<Parameter> getParameters() {
+        return parameters;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    @SuppressWarnings("unchecked")
+    public T setParameters(final NodeList<Parameter> parameters) {
+        assertNotNull(parameters);
+        if (parameters == this.parameters) {
+            return (T) this;
+        }
+        notifyPropertyChange(ObservableProperty.PARAMETERS, this.parameters, parameters);
+        if (this.parameters != null)
+            this.parameters.setParentNode(null);
+        this.parameters = parameters;
+        setAsParentNodeOf(parameters);
+        return (T) this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public NodeList<ReferenceType> getThrownExceptions() {
+        return thrownExceptions;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    @SuppressWarnings("unchecked")
+    public T setThrownExceptions(final NodeList<ReferenceType> thrownExceptions) {
+        assertNotNull(thrownExceptions);
+        if (thrownExceptions == this.thrownExceptions) {
+            return (T) this;
+        }
+        notifyPropertyChange(ObservableProperty.THROWN_EXCEPTIONS, this.thrownExceptions, thrownExceptions);
+        if (this.thrownExceptions != null)
+            this.thrownExceptions.setParentNode(null);
+        this.thrownExceptions = thrownExceptions;
+        setAsParentNodeOf(thrownExceptions);
+        return (T) this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public NodeList<TypeParameter> getTypeParameters() {
+        return typeParameters;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    @SuppressWarnings("unchecked")
+    public T setTypeParameters(final NodeList<TypeParameter> typeParameters) {
+        assertNotNull(typeParameters);
+        if (typeParameters == this.typeParameters) {
+            return (T) this;
+        }
+        notifyPropertyChange(ObservableProperty.TYPE_PARAMETERS, this.typeParameters, typeParameters);
+        if (this.typeParameters != null)
+            this.typeParameters.setParentNode(null);
+        this.typeParameters = typeParameters;
+        setAsParentNodeOf(typeParameters);
+        return (T) this;
+    }
+
+    public String getDeclarationAsString(boolean includingModifiers, boolean includingThrows) {
+        return getDeclarationAsString(includingModifiers, includingThrows, true);
+    }
+
+    public String getDeclarationAsString() {
+        return getDeclarationAsString(true, true, true);
+    }
+
+    public abstract String getDeclarationAsString(boolean includingModifiers, boolean includingThrows, boolean includingParameterName);
+
+    protected String appendThrowsIfRequested(boolean includingThrows) {
+        StringBuilder sb = new StringBuilder();
+        if (includingThrows) {
+            boolean firstThrow = true;
+            for (ReferenceType thr : getThrownExceptions()) {
+                if (firstThrow) {
+                    firstThrow = false;
+                    sb.append(" throws ");
+                } else {
+                    sb.append(", ");
+                }
+                sb.append(thr.toString(prettyPrinterNoCommentsConfiguration));
+            }
+        }
+        return sb.toString();
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public boolean remove(Node node) {
+        if (node == null)
+            return false;
+        for (int i = 0; i < parameters.size(); i++) {
+            if (parameters.get(i) == node) {
+                parameters.remove(i);
+                return true;
+            }
+        }
+        if (receiverParameter != null) {
+            if (node == receiverParameter) {
+                removeReceiverParameter();
+                return true;
+            }
+        }
+        for (int i = 0; i < thrownExceptions.size(); i++) {
+            if (thrownExceptions.get(i) == node) {
+                thrownExceptions.remove(i);
+                return true;
+            }
+        }
+        for (int i = 0; i < typeParameters.size(); i++) {
+            if (typeParameters.get(i) == node) {
+                typeParameters.remove(i);
+                return true;
+            }
+        }
+        return super.remove(node);
+    }
+
+    /**
+     * A method or constructor signature.
+     * <p/>Note that since JavaParser has no real knowledge of types - only the text found in the source file - using
+     * this will fail in some cases. (java.util.String != String for example, and generics are not taken into account.)
+     */
+    public static class Signature {
+
+        private final String name;
+
+        private final List<Type> parameterTypes;
+
+        private Signature(String name, List<Type> parameterTypes) {
+            this.name = name;
+            this.parameterTypes = parameterTypes;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public List<Type> getParameterTypes() {
+            return parameterTypes;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            if (o == null || getClass() != o.getClass())
+                return false;
+            Signature signature = (Signature) o;
+            if (!name.equals(signature.name))
+                return false;
+            if (!parameterTypes.equals(signature.parameterTypes))
+                return false;
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = name.hashCode();
+            result = 31 * result + parameterTypes.hashCode();
+            return result;
+        }
+
+        public String asString() {
+            return parameterTypes.stream().map(Type::asString).collect(joining(", ", name + "(", ")"));
+        }
+
+        @Override
+        public String toString() {
+            return asString();
+        }
+    }
+
+    public Signature getSignature() {
+        return new Signature(getName().getIdentifier(), getParameters().stream().map(this::getTypeWithVarargsAsArray).map(this::stripGenerics).map(this::stripAnnotations).collect(toList()));
+    }
+
+    private Type stripAnnotations(Type type) {
+        if (type instanceof NodeWithAnnotations) {
+            ((NodeWithAnnotations) type).setAnnotations(new NodeList<>());
+        }
+        return type;
+    }
+
+    private Type stripGenerics(Type type) {
+        if (type instanceof NodeWithTypeArguments) {
+            ((NodeWithTypeArguments) type).setTypeArguments((NodeList<Type>) null);
+        }
+        return type;
+    }
+
+    private Type getTypeWithVarargsAsArray(Parameter p) {
+        /* A signature includes the varargs ellipsis.
+         This is a field on parameter which we lose when we only get the type,
+         so we represent it as an additional [] on the type. */
+        Type t = p.getType().clone();
+        if (p.isVarArgs()) {
+            t = new ArrayType(t);
+        }
+        return t;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.CloneGenerator")
+    public CallableDeclaration<?> clone() {
+        return (CallableDeclaration<?>) accept(new CloneVisitor(), null);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.GetMetaModelGenerator")
+    public CallableDeclarationMetaModel getMetaModel() {
+        return JavaParserMetaModel.callableDeclarationMetaModel;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.ReplaceMethodGenerator")
+    public boolean replace(Node node, Node replacementNode) {
+        if (node == null)
+            return false;
+        if (node == name) {
+            setName((SimpleName) replacementNode);
+            return true;
+        }
+        for (int i = 0; i < parameters.size(); i++) {
+            if (parameters.get(i) == node) {
+                parameters.set(i, (Parameter) replacementNode);
+                return true;
+            }
+        }
+        if (receiverParameter != null) {
+            if (node == receiverParameter) {
+                setReceiverParameter((ReceiverParameter) replacementNode);
+                return true;
+            }
+        }
+        for (int i = 0; i < thrownExceptions.size(); i++) {
+            if (thrownExceptions.get(i) == node) {
+                thrownExceptions.set(i, (ReferenceType) replacementNode);
+                return true;
+            }
+        }
+        for (int i = 0; i < typeParameters.size(); i++) {
+            if (typeParameters.get(i) == node) {
+                typeParameters.set(i, (TypeParameter) replacementNode);
+                return true;
+            }
+        }
+        return super.replace(node, replacementNode);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isCallableDeclaration() {
+        return true;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public CallableDeclaration asCallableDeclaration() {
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifCallableDeclaration(Consumer<CallableDeclaration> action) {
+        action.accept(this);
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public Optional<ReceiverParameter> getReceiverParameter() {
+        return Optional.ofNullable(receiverParameter);
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    @SuppressWarnings("unchecked")
+    public T setReceiverParameter(final ReceiverParameter receiverParameter) {
+        if (receiverParameter == this.receiverParameter) {
+            return (T) this;
+        }
+        notifyPropertyChange(ObservableProperty.RECEIVER_PARAMETER, this.receiverParameter, receiverParameter);
+        if (this.receiverParameter != null)
+            this.receiverParameter.setParentNode(null);
+        this.receiverParameter = receiverParameter;
+        setAsParentNodeOf(receiverParameter);
+        return (T) this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public CallableDeclaration removeReceiverParameter() {
+        return setReceiverParameter((ReceiverParameter) null);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<CallableDeclaration> toCallableDeclaration() {
+        return Optional.of(this);
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/body/ClassOrInterfaceDeclaration.java b/javaparser-core/src/main/java/com/github/javaparser/ast/body/ClassOrInterfaceDeclaration.java
new file mode 100644
index 0000000..a275066
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/body/ClassOrInterfaceDeclaration.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.ast.body;
+
+import com.github.javaparser.TokenRange;
+import com.github.javaparser.ast.AllFieldsConstructor;
+import com.github.javaparser.ast.Modifier;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.expr.AnnotationExpr;
+import com.github.javaparser.ast.expr.SimpleName;
+import com.github.javaparser.ast.nodeTypes.NodeWithConstructors;
+import com.github.javaparser.ast.nodeTypes.NodeWithExtends;
+import com.github.javaparser.ast.nodeTypes.NodeWithImplements;
+import com.github.javaparser.ast.nodeTypes.NodeWithTypeParameters;
+import com.github.javaparser.ast.nodeTypes.modifiers.NodeWithAbstractModifier;
+import com.github.javaparser.ast.nodeTypes.modifiers.NodeWithFinalModifier;
+import com.github.javaparser.ast.observer.ObservableProperty;
+import com.github.javaparser.ast.stmt.LocalClassDeclarationStmt;
+import com.github.javaparser.ast.type.ClassOrInterfaceType;
+import com.github.javaparser.ast.type.TypeParameter;
+import com.github.javaparser.ast.visitor.CloneVisitor;
+import com.github.javaparser.ast.visitor.GenericVisitor;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+import com.github.javaparser.metamodel.ClassOrInterfaceDeclarationMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import com.github.javaparser.resolution.Resolvable;
+import com.github.javaparser.resolution.declarations.ResolvedAnnotationDeclaration;
+import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration;
+import javax.annotation.Generated;
+import java.util.EnumSet;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+import java.util.function.Consumer;
+import java.util.Optional;
+
+/**
+ * A definition of a class or interface.<br/><code>class X { ... }</code>
+ *
+ * @author Julio Vilmar Gesser
+ */
+public final class ClassOrInterfaceDeclaration extends TypeDeclaration<ClassOrInterfaceDeclaration> implements NodeWithImplements<ClassOrInterfaceDeclaration>, NodeWithExtends<ClassOrInterfaceDeclaration>, NodeWithTypeParameters<ClassOrInterfaceDeclaration>, NodeWithAbstractModifier<ClassOrInterfaceDeclaration>, NodeWithFinalModifier<ClassOrInterfaceDeclaration>, NodeWithConstructors<ClassOrInterfaceDeclaration>, Resolvable<ResolvedReferenceTypeDeclaration> {
+
+    private boolean isInterface;
+
+    private NodeList<TypeParameter> typeParameters;
+
+    // Can contain more than one item if this is an interface
+    private NodeList<ClassOrInterfaceType> extendedTypes;
+
+    private NodeList<ClassOrInterfaceType> implementedTypes;
+
+    public ClassOrInterfaceDeclaration() {
+        this(null, EnumSet.noneOf(Modifier.class), new NodeList<>(), false, new SimpleName(), new NodeList<>(), new NodeList<>(), new NodeList<>(), new NodeList<>());
+    }
+
+    public ClassOrInterfaceDeclaration(final EnumSet<Modifier> modifiers, final boolean isInterface, final String name) {
+        this(null, modifiers, new NodeList<>(), isInterface, new SimpleName(name), new NodeList<>(), new NodeList<>(), new NodeList<>(), new NodeList<>());
+    }
+
+    @AllFieldsConstructor
+    public ClassOrInterfaceDeclaration(final EnumSet<Modifier> modifiers, final NodeList<AnnotationExpr> annotations, final boolean isInterface, final SimpleName name, final NodeList<TypeParameter> typeParameters, final NodeList<ClassOrInterfaceType> extendedTypes, final NodeList<ClassOrInterfaceType> implementedTypes, final NodeList<BodyDeclaration<?>> members) {
+        this(null, modifiers, annotations, isInterface, name, typeParameters, extendedTypes, implementedTypes, members);
+    }
+
+    /**
+     * This constructor is used by the parser and is considered private.
+     */
+    @Generated("com.github.javaparser.generator.core.node.MainConstructorGenerator")
+    public ClassOrInterfaceDeclaration(TokenRange tokenRange, EnumSet<Modifier> modifiers, NodeList<AnnotationExpr> annotations, boolean isInterface, SimpleName name, NodeList<TypeParameter> typeParameters, NodeList<ClassOrInterfaceType> extendedTypes, NodeList<ClassOrInterfaceType> implementedTypes, NodeList<BodyDeclaration<?>> members) {
+        super(tokenRange, modifiers, annotations, name, members);
+        setInterface(isInterface);
+        setTypeParameters(typeParameters);
+        setExtendedTypes(extendedTypes);
+        setImplementedTypes(implementedTypes);
+        customInitialization();
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) {
+        return v.visit(this, arg);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <A> void accept(final VoidVisitor<A> v, final A arg) {
+        v.visit(this, arg);
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public NodeList<ClassOrInterfaceType> getExtendedTypes() {
+        return extendedTypes;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public NodeList<ClassOrInterfaceType> getImplementedTypes() {
+        return implementedTypes;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public NodeList<TypeParameter> getTypeParameters() {
+        return typeParameters;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public boolean isInterface() {
+        return isInterface;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public ClassOrInterfaceDeclaration setExtendedTypes(final NodeList<ClassOrInterfaceType> extendedTypes) {
+        assertNotNull(extendedTypes);
+        if (extendedTypes == this.extendedTypes) {
+            return (ClassOrInterfaceDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.EXTENDED_TYPES, this.extendedTypes, extendedTypes);
+        if (this.extendedTypes != null)
+            this.extendedTypes.setParentNode(null);
+        this.extendedTypes = extendedTypes;
+        setAsParentNodeOf(extendedTypes);
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public ClassOrInterfaceDeclaration setImplementedTypes(final NodeList<ClassOrInterfaceType> implementedTypes) {
+        assertNotNull(implementedTypes);
+        if (implementedTypes == this.implementedTypes) {
+            return (ClassOrInterfaceDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.IMPLEMENTED_TYPES, this.implementedTypes, implementedTypes);
+        if (this.implementedTypes != null)
+            this.implementedTypes.setParentNode(null);
+        this.implementedTypes = implementedTypes;
+        setAsParentNodeOf(implementedTypes);
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public ClassOrInterfaceDeclaration setInterface(final boolean isInterface) {
+        if (isInterface == this.isInterface) {
+            return (ClassOrInterfaceDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.INTERFACE, this.isInterface, isInterface);
+        this.isInterface = isInterface;
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public ClassOrInterfaceDeclaration setTypeParameters(final NodeList<TypeParameter> typeParameters) {
+        assertNotNull(typeParameters);
+        if (typeParameters == this.typeParameters) {
+            return (ClassOrInterfaceDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.TYPE_PARAMETERS, this.typeParameters, typeParameters);
+        if (this.typeParameters != null)
+            this.typeParameters.setParentNode(null);
+        this.typeParameters = typeParameters;
+        setAsParentNodeOf(typeParameters);
+        return this;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public boolean remove(Node node) {
+        if (node == null)
+            return false;
+        for (int i = 0; i < extendedTypes.size(); i++) {
+            if (extendedTypes.get(i) == node) {
+                extendedTypes.remove(i);
+                return true;
+            }
+        }
+        for (int i = 0; i < implementedTypes.size(); i++) {
+            if (implementedTypes.get(i) == node) {
+                implementedTypes.remove(i);
+                return true;
+            }
+        }
+        for (int i = 0; i < typeParameters.size(); i++) {
+            if (typeParameters.get(i) == node) {
+                typeParameters.remove(i);
+                return true;
+            }
+        }
+        return super.remove(node);
+    }
+
+    /**
+     * @return is this class's parent a LocalClassDeclarationStmt ?
+     */
+    public boolean isLocalClassDeclaration() {
+        return getParentNode().map(p -> p instanceof LocalClassDeclarationStmt).orElse(false);
+    }
+
+    /**
+     * @return is this an inner class?
+     * NOTE: many people are confused over terminology. Refer to https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html .
+     */
+    public boolean isInnerClass() {
+        return isNestedType() && !isInterface && !isStatic();
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.CloneGenerator")
+    public ClassOrInterfaceDeclaration clone() {
+        return (ClassOrInterfaceDeclaration) accept(new CloneVisitor(), null);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.GetMetaModelGenerator")
+    public ClassOrInterfaceDeclarationMetaModel getMetaModel() {
+        return JavaParserMetaModel.classOrInterfaceDeclarationMetaModel;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.ReplaceMethodGenerator")
+    public boolean replace(Node node, Node replacementNode) {
+        if (node == null)
+            return false;
+        for (int i = 0; i < extendedTypes.size(); i++) {
+            if (extendedTypes.get(i) == node) {
+                extendedTypes.set(i, (ClassOrInterfaceType) replacementNode);
+                return true;
+            }
+        }
+        for (int i = 0; i < implementedTypes.size(); i++) {
+            if (implementedTypes.get(i) == node) {
+                implementedTypes.set(i, (ClassOrInterfaceType) replacementNode);
+                return true;
+            }
+        }
+        for (int i = 0; i < typeParameters.size(); i++) {
+            if (typeParameters.get(i) == node) {
+                typeParameters.set(i, (TypeParameter) replacementNode);
+                return true;
+            }
+        }
+        return super.replace(node, replacementNode);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isClassOrInterfaceDeclaration() {
+        return true;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public ClassOrInterfaceDeclaration asClassOrInterfaceDeclaration() {
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifClassOrInterfaceDeclaration(Consumer<ClassOrInterfaceDeclaration> action) {
+        action.accept(this);
+    }
+
+    @Override
+    public ResolvedReferenceTypeDeclaration resolve() {
+        return getSymbolResolver().resolveDeclaration(this, ResolvedReferenceTypeDeclaration.class);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<ClassOrInterfaceDeclaration> toClassOrInterfaceDeclaration() {
+        return Optional.of(this);
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/body/ConstructorDeclaration.java b/javaparser-core/src/main/java/com/github/javaparser/ast/body/ConstructorDeclaration.java
new file mode 100644
index 0000000..ab1dad9
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/body/ConstructorDeclaration.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2017 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.ast.body;
+
+import com.github.javaparser.ast.AccessSpecifier;
+import com.github.javaparser.ast.AllFieldsConstructor;
+import com.github.javaparser.ast.Modifier;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.expr.AnnotationExpr;
+import com.github.javaparser.ast.expr.SimpleName;
+import com.github.javaparser.ast.nodeTypes.*;
+import com.github.javaparser.ast.nodeTypes.modifiers.NodeWithAccessModifiers;
+import com.github.javaparser.ast.observer.ObservableProperty;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.ast.type.ReferenceType;
+import com.github.javaparser.ast.type.TypeParameter;
+import com.github.javaparser.ast.visitor.GenericVisitor;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+import java.util.EnumSet;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.visitor.CloneVisitor;
+import com.github.javaparser.metamodel.ConstructorDeclarationMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import javax.annotation.Generated;
+import com.github.javaparser.TokenRange;
+import com.github.javaparser.resolution.Resolvable;
+import com.github.javaparser.resolution.declarations.ResolvedConstructorDeclaration;
+import java.util.function.Consumer;
+import java.util.Optional;
+
+/**
+ * A constructor declaration: <code>class X { X() { } }</code> where X(){} is the constructor declaration.
+ *
+ * <br/>All annotations preceding the name will be set on this object, not on the class.
+ * JavaParser doesn't know if it they are applicable to the method or the class.
+ *
+ * @author Julio Vilmar Gesser
+ */
+public final class ConstructorDeclaration extends CallableDeclaration<ConstructorDeclaration> implements NodeWithBlockStmt<ConstructorDeclaration>, NodeWithAccessModifiers<ConstructorDeclaration>, NodeWithJavadoc<ConstructorDeclaration>, NodeWithSimpleName<ConstructorDeclaration>, NodeWithParameters<ConstructorDeclaration>, NodeWithThrownExceptions<ConstructorDeclaration>, NodeWithTypeParameters<ConstructorDeclaration>, Resolvable<ResolvedConstructorDeclaration> {
+
+    private BlockStmt body;
+
+    public ConstructorDeclaration() {
+        this(null, EnumSet.noneOf(Modifier.class), new NodeList<>(), new NodeList<>(), new SimpleName(), new NodeList<>(), new NodeList<>(), new BlockStmt(), null);
+    }
+
+    public ConstructorDeclaration(String name) {
+        this(null, EnumSet.of(Modifier.PUBLIC), new NodeList<>(), new NodeList<>(), new SimpleName(name), new NodeList<>(), new NodeList<>(), new BlockStmt(), null);
+    }
+
+    public ConstructorDeclaration(EnumSet<Modifier> modifiers, String name) {
+        this(null, modifiers, new NodeList<>(), new NodeList<>(), new SimpleName(name), new NodeList<>(), new NodeList<>(), new BlockStmt(), null);
+    }
+
+    public ConstructorDeclaration(EnumSet<Modifier> modifiers, NodeList<AnnotationExpr> annotations, NodeList<TypeParameter> typeParameters, SimpleName name, NodeList<Parameter> parameters, NodeList<ReferenceType> thrownExceptions, BlockStmt body) {
+        this(null, modifiers, annotations, typeParameters, name, parameters, thrownExceptions, body, null);
+    }
+
+    @AllFieldsConstructor
+    public ConstructorDeclaration(EnumSet<Modifier> modifiers, NodeList<AnnotationExpr> annotations, NodeList<TypeParameter> typeParameters, SimpleName name, NodeList<Parameter> parameters, NodeList<ReferenceType> thrownExceptions, BlockStmt body, ReceiverParameter receiverParameter) {
+        this(null, modifiers, annotations, typeParameters, name, parameters, thrownExceptions, body, receiverParameter);
+    }
+
+    /**
+     * This constructor is used by the parser and is considered private.
+     */
+    @Generated("com.github.javaparser.generator.core.node.MainConstructorGenerator")
+    public ConstructorDeclaration(TokenRange tokenRange, EnumSet<Modifier> modifiers, NodeList<AnnotationExpr> annotations, NodeList<TypeParameter> typeParameters, SimpleName name, NodeList<Parameter> parameters, NodeList<ReferenceType> thrownExceptions, BlockStmt body, ReceiverParameter receiverParameter) {
+        super(tokenRange, modifiers, annotations, typeParameters, name, parameters, thrownExceptions, receiverParameter);
+        setBody(body);
+        customInitialization();
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) {
+        return v.visit(this, arg);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <A> void accept(final VoidVisitor<A> v, final A arg) {
+        v.visit(this, arg);
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public BlockStmt getBody() {
+        return body;
+    }
+
+    /**
+     * Sets the body
+     *
+     * @param body the body, can not be null
+     * @return this, the ConstructorDeclaration
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public ConstructorDeclaration setBody(final BlockStmt body) {
+        assertNotNull(body);
+        if (body == this.body) {
+            return (ConstructorDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.BODY, this.body, body);
+        if (this.body != null)
+            this.body.setParentNode(null);
+        this.body = body;
+        setAsParentNodeOf(body);
+        return this;
+    }
+
+    @Override
+    public ConstructorDeclaration setModifiers(final EnumSet<Modifier> modifiers) {
+        return super.setModifiers(modifiers);
+    }
+
+    @Override
+    public ConstructorDeclaration setName(final SimpleName name) {
+        return super.setName(name);
+    }
+
+    @Override
+    public ConstructorDeclaration setParameters(final NodeList<Parameter> parameters) {
+        return super.setParameters(parameters);
+    }
+
+    @Override
+    public ConstructorDeclaration setThrownExceptions(final NodeList<ReferenceType> thrownExceptions) {
+        return super.setThrownExceptions(thrownExceptions);
+    }
+
+    @Override
+    public ConstructorDeclaration setTypeParameters(final NodeList<TypeParameter> typeParameters) {
+        return super.setTypeParameters(typeParameters);
+    }
+
+    /**
+     * The declaration returned has this schema:
+     * <p>
+     * [accessSpecifier] className ([paramType [paramName]])
+     * [throws exceptionsList]
+     */
+    @Override
+    public String getDeclarationAsString(boolean includingModifiers, boolean includingThrows, boolean includingParameterName) {
+        StringBuilder sb = new StringBuilder();
+        if (includingModifiers) {
+            AccessSpecifier accessSpecifier = Modifier.getAccessSpecifier(getModifiers());
+            sb.append(accessSpecifier.asString());
+            sb.append(accessSpecifier == AccessSpecifier.DEFAULT ? "" : " ");
+        }
+        sb.append(getName());
+        sb.append("(");
+        boolean firstParam = true;
+        for (Parameter param : getParameters()) {
+            if (firstParam) {
+                firstParam = false;
+            } else {
+                sb.append(", ");
+            }
+            if (includingParameterName) {
+                sb.append(param.toString(prettyPrinterNoCommentsConfiguration));
+            } else {
+                sb.append(param.getType().toString(prettyPrinterNoCommentsConfiguration));
+            }
+        }
+        sb.append(")");
+        sb.append(appendThrowsIfRequested(includingThrows));
+        return sb.toString();
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public boolean remove(Node node) {
+        if (node == null)
+            return false;
+        return super.remove(node);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.CloneGenerator")
+    public ConstructorDeclaration clone() {
+        return (ConstructorDeclaration) accept(new CloneVisitor(), null);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.GetMetaModelGenerator")
+    public ConstructorDeclarationMetaModel getMetaModel() {
+        return JavaParserMetaModel.constructorDeclarationMetaModel;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.ReplaceMethodGenerator")
+    public boolean replace(Node node, Node replacementNode) {
+        if (node == null)
+            return false;
+        if (node == body) {
+            setBody((BlockStmt) replacementNode);
+            return true;
+        }
+        return super.replace(node, replacementNode);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isConstructorDeclaration() {
+        return true;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public ConstructorDeclaration asConstructorDeclaration() {
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifConstructorDeclaration(Consumer<ConstructorDeclaration> action) {
+        action.accept(this);
+    }
+
+    @Override
+    public ResolvedConstructorDeclaration resolve() {
+        return getSymbolResolver().resolveDeclaration(this, ResolvedConstructorDeclaration.class);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<ConstructorDeclaration> toConstructorDeclaration() {
+        return Optional.of(this);
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/body/EnumConstantDeclaration.java b/javaparser-core/src/main/java/com/github/javaparser/ast/body/EnumConstantDeclaration.java
new file mode 100644
index 0000000..5a331e4
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/body/EnumConstantDeclaration.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.ast.body;
+
+import com.github.javaparser.ast.AllFieldsConstructor;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.expr.AnnotationExpr;
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.expr.SimpleName;
+import com.github.javaparser.ast.nodeTypes.NodeWithArguments;
+import com.github.javaparser.ast.nodeTypes.NodeWithJavadoc;
+import com.github.javaparser.ast.nodeTypes.NodeWithSimpleName;
+import com.github.javaparser.ast.observer.ObservableProperty;
+import com.github.javaparser.ast.visitor.GenericVisitor;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+import java.util.Arrays;
+import java.util.List;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.visitor.CloneVisitor;
+import com.github.javaparser.metamodel.EnumConstantDeclarationMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import javax.annotation.Generated;
+import com.github.javaparser.TokenRange;
+import com.github.javaparser.resolution.Resolvable;
+import com.github.javaparser.resolution.declarations.ResolvedConstructorDeclaration;
+import com.github.javaparser.resolution.declarations.ResolvedEnumConstantDeclaration;
+import java.util.function.Consumer;
+import java.util.Optional;
+
+/**
+ * One of the values an enum can take. A(1) and B(2) in this example: <code>enum X { A(1), B(2) }</code>
+ *
+ * @author Julio Vilmar Gesser
+ */
+public final class EnumConstantDeclaration extends BodyDeclaration<EnumConstantDeclaration> implements NodeWithJavadoc<EnumConstantDeclaration>, NodeWithSimpleName<EnumConstantDeclaration>, NodeWithArguments<EnumConstantDeclaration>, Resolvable<ResolvedEnumConstantDeclaration> {
+
+    private SimpleName name;
+
+    private NodeList<Expression> arguments;
+
+    private NodeList<BodyDeclaration<?>> classBody;
+
+    public EnumConstantDeclaration() {
+        this(null, new NodeList<>(), new SimpleName(), new NodeList<>(), new NodeList<>());
+    }
+
+    public EnumConstantDeclaration(String name) {
+        this(null, new NodeList<>(), new SimpleName(name), new NodeList<>(), new NodeList<>());
+    }
+
+    @AllFieldsConstructor
+    public EnumConstantDeclaration(NodeList<AnnotationExpr> annotations, SimpleName name, NodeList<Expression> arguments, NodeList<BodyDeclaration<?>> classBody) {
+        this(null, annotations, name, arguments, classBody);
+    }
+
+    /**
+     * This constructor is used by the parser and is considered private.
+     */
+    @Generated("com.github.javaparser.generator.core.node.MainConstructorGenerator")
+    public EnumConstantDeclaration(TokenRange tokenRange, NodeList<AnnotationExpr> annotations, SimpleName name, NodeList<Expression> arguments, NodeList<BodyDeclaration<?>> classBody) {
+        super(tokenRange, annotations);
+        setName(name);
+        setArguments(arguments);
+        setClassBody(classBody);
+        customInitialization();
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) {
+        return v.visit(this, arg);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <A> void accept(final VoidVisitor<A> v, final A arg) {
+        v.visit(this, arg);
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public NodeList<Expression> getArguments() {
+        return arguments;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public NodeList<BodyDeclaration<?>> getClassBody() {
+        return classBody;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public SimpleName getName() {
+        return name;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public EnumConstantDeclaration setArguments(final NodeList<Expression> arguments) {
+        assertNotNull(arguments);
+        if (arguments == this.arguments) {
+            return (EnumConstantDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.ARGUMENTS, this.arguments, arguments);
+        if (this.arguments != null)
+            this.arguments.setParentNode(null);
+        this.arguments = arguments;
+        setAsParentNodeOf(arguments);
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public EnumConstantDeclaration setClassBody(final NodeList<BodyDeclaration<?>> classBody) {
+        assertNotNull(classBody);
+        if (classBody == this.classBody) {
+            return (EnumConstantDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.CLASS_BODY, this.classBody, classBody);
+        if (this.classBody != null)
+            this.classBody.setParentNode(null);
+        this.classBody = classBody;
+        setAsParentNodeOf(classBody);
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public EnumConstantDeclaration setName(final SimpleName name) {
+        assertNotNull(name);
+        if (name == this.name) {
+            return (EnumConstantDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.NAME, this.name, name);
+        if (this.name != null)
+            this.name.setParentNode(null);
+        this.name = name;
+        setAsParentNodeOf(name);
+        return this;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public boolean remove(Node node) {
+        if (node == null)
+            return false;
+        for (int i = 0; i < arguments.size(); i++) {
+            if (arguments.get(i) == node) {
+                arguments.remove(i);
+                return true;
+            }
+        }
+        for (int i = 0; i < classBody.size(); i++) {
+            if (classBody.get(i) == node) {
+                classBody.remove(i);
+                return true;
+            }
+        }
+        return super.remove(node);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.CloneGenerator")
+    public EnumConstantDeclaration clone() {
+        return (EnumConstantDeclaration) accept(new CloneVisitor(), null);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.GetMetaModelGenerator")
+    public EnumConstantDeclarationMetaModel getMetaModel() {
+        return JavaParserMetaModel.enumConstantDeclarationMetaModel;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.ReplaceMethodGenerator")
+    public boolean replace(Node node, Node replacementNode) {
+        if (node == null)
+            return false;
+        for (int i = 0; i < arguments.size(); i++) {
+            if (arguments.get(i) == node) {
+                arguments.set(i, (Expression) replacementNode);
+                return true;
+            }
+        }
+        for (int i = 0; i < classBody.size(); i++) {
+            if (classBody.get(i) == node) {
+                classBody.set(i, (BodyDeclaration) replacementNode);
+                return true;
+            }
+        }
+        if (node == name) {
+            setName((SimpleName) replacementNode);
+            return true;
+        }
+        return super.replace(node, replacementNode);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isEnumConstantDeclaration() {
+        return true;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public EnumConstantDeclaration asEnumConstantDeclaration() {
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifEnumConstantDeclaration(Consumer<EnumConstantDeclaration> action) {
+        action.accept(this);
+    }
+
+    @Override
+    public ResolvedEnumConstantDeclaration resolve() {
+        return getSymbolResolver().resolveDeclaration(this, ResolvedEnumConstantDeclaration.class);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<EnumConstantDeclaration> toEnumConstantDeclaration() {
+        return Optional.of(this);
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/body/EnumDeclaration.java b/javaparser-core/src/main/java/com/github/javaparser/ast/body/EnumDeclaration.java
new file mode 100644
index 0000000..44fb1e4
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/body/EnumDeclaration.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.ast.body;
+
+import com.github.javaparser.TokenRange;
+import com.github.javaparser.ast.AllFieldsConstructor;
+import com.github.javaparser.ast.Modifier;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.expr.AnnotationExpr;
+import com.github.javaparser.ast.expr.SimpleName;
+import com.github.javaparser.ast.nodeTypes.NodeWithConstructors;
+import com.github.javaparser.ast.nodeTypes.NodeWithImplements;
+import com.github.javaparser.ast.observer.ObservableProperty;
+import com.github.javaparser.ast.type.ClassOrInterfaceType;
+import com.github.javaparser.ast.visitor.CloneVisitor;
+import com.github.javaparser.ast.visitor.GenericVisitor;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+import com.github.javaparser.metamodel.EnumDeclarationMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import com.github.javaparser.resolution.Resolvable;
+import com.github.javaparser.resolution.declarations.ResolvedEnumDeclaration;
+import javax.annotation.Generated;
+import java.util.EnumSet;
+import static com.github.javaparser.utils.Utils.assertNonEmpty;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+import java.util.function.Consumer;
+import java.util.Optional;
+
+/**
+ * The declaration of an enum.<br/><code>enum X { ... }</code>
+ *
+ * @author Julio Vilmar Gesser
+ */
+public final class EnumDeclaration extends TypeDeclaration<EnumDeclaration> implements NodeWithImplements<EnumDeclaration>, NodeWithConstructors<EnumDeclaration>, Resolvable<ResolvedEnumDeclaration> {
+
+    private NodeList<ClassOrInterfaceType> implementedTypes;
+
+    private NodeList<EnumConstantDeclaration> entries;
+
+    public EnumDeclaration() {
+        this(null, EnumSet.noneOf(Modifier.class), new NodeList<>(), new SimpleName(), new NodeList<>(), new NodeList<>(), new NodeList<>());
+    }
+
+    public EnumDeclaration(EnumSet<Modifier> modifiers, String name) {
+        this(null, modifiers, new NodeList<>(), new SimpleName(name), new NodeList<>(), new NodeList<>(), new NodeList<>());
+    }
+
+    @AllFieldsConstructor
+    public EnumDeclaration(EnumSet<Modifier> modifiers, NodeList<AnnotationExpr> annotations, SimpleName name, NodeList<ClassOrInterfaceType> implementedTypes, NodeList<EnumConstantDeclaration> entries, NodeList<BodyDeclaration<?>> members) {
+        this(null, modifiers, annotations, name, implementedTypes, entries, members);
+    }
+
+    /**
+     * This constructor is used by the parser and is considered private.
+     */
+    @Generated("com.github.javaparser.generator.core.node.MainConstructorGenerator")
+    public EnumDeclaration(TokenRange tokenRange, EnumSet<Modifier> modifiers, NodeList<AnnotationExpr> annotations, SimpleName name, NodeList<ClassOrInterfaceType> implementedTypes, NodeList<EnumConstantDeclaration> entries, NodeList<BodyDeclaration<?>> members) {
+        super(tokenRange, modifiers, annotations, name, members);
+        setImplementedTypes(implementedTypes);
+        setEntries(entries);
+        customInitialization();
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) {
+        return v.visit(this, arg);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <A> void accept(final VoidVisitor<A> v, final A arg) {
+        v.visit(this, arg);
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public NodeList<EnumConstantDeclaration> getEntries() {
+        return entries;
+    }
+
+    public EnumConstantDeclaration getEntry(int i) {
+        return getEntries().get(i);
+    }
+
+    public EnumDeclaration setEntry(int i, EnumConstantDeclaration element) {
+        getEntries().set(i, element);
+        return this;
+    }
+
+    public EnumDeclaration addEntry(EnumConstantDeclaration element) {
+        getEntries().add(element);
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public NodeList<ClassOrInterfaceType> getImplementedTypes() {
+        return implementedTypes;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public EnumDeclaration setEntries(final NodeList<EnumConstantDeclaration> entries) {
+        assertNotNull(entries);
+        if (entries == this.entries) {
+            return (EnumDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.ENTRIES, this.entries, entries);
+        if (this.entries != null)
+            this.entries.setParentNode(null);
+        this.entries = entries;
+        setAsParentNodeOf(entries);
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public EnumDeclaration setImplementedTypes(final NodeList<ClassOrInterfaceType> implementedTypes) {
+        assertNotNull(implementedTypes);
+        if (implementedTypes == this.implementedTypes) {
+            return (EnumDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.IMPLEMENTED_TYPES, this.implementedTypes, implementedTypes);
+        if (this.implementedTypes != null)
+            this.implementedTypes.setParentNode(null);
+        this.implementedTypes = implementedTypes;
+        setAsParentNodeOf(implementedTypes);
+        return this;
+    }
+
+    public EnumConstantDeclaration addEnumConstant(String name) {
+        assertNonEmpty(name);
+        EnumConstantDeclaration enumConstant = new EnumConstantDeclaration(name);
+        getEntries().add(enumConstant);
+        return enumConstant;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public boolean remove(Node node) {
+        if (node == null)
+            return false;
+        for (int i = 0; i < entries.size(); i++) {
+            if (entries.get(i) == node) {
+                entries.remove(i);
+                return true;
+            }
+        }
+        for (int i = 0; i < implementedTypes.size(); i++) {
+            if (implementedTypes.get(i) == node) {
+                implementedTypes.remove(i);
+                return true;
+            }
+        }
+        return super.remove(node);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.CloneGenerator")
+    public EnumDeclaration clone() {
+        return (EnumDeclaration) accept(new CloneVisitor(), null);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.GetMetaModelGenerator")
+    public EnumDeclarationMetaModel getMetaModel() {
+        return JavaParserMetaModel.enumDeclarationMetaModel;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.ReplaceMethodGenerator")
+    public boolean replace(Node node, Node replacementNode) {
+        if (node == null)
+            return false;
+        for (int i = 0; i < entries.size(); i++) {
+            if (entries.get(i) == node) {
+                entries.set(i, (EnumConstantDeclaration) replacementNode);
+                return true;
+            }
+        }
+        for (int i = 0; i < implementedTypes.size(); i++) {
+            if (implementedTypes.get(i) == node) {
+                implementedTypes.set(i, (ClassOrInterfaceType) replacementNode);
+                return true;
+            }
+        }
+        return super.replace(node, replacementNode);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public boolean isEnumDeclaration() {
+        return true;
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public EnumDeclaration asEnumDeclaration() {
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public void ifEnumDeclaration(Consumer<EnumDeclaration> action) {
+        action.accept(this);
+    }
+
+    @Override
+    public ResolvedEnumDeclaration resolve() {
+        return getSymbolResolver().resolveDeclaration(this, ResolvedEnumDeclaration.class);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
+    public Optional<EnumDeclaration> toEnumDeclaration() {
+        return Optional.of(this);
+    }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/body/FieldDeclaration.java b/javaparser-core/src/main/java/com/github/javaparser/ast/body/FieldDeclaration.java
new file mode 100644
index 0000000..547e95a
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/body/FieldDeclaration.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.ast.body;
+
+import com.github.javaparser.ast.AllFieldsConstructor;
+import com.github.javaparser.ast.Modifier;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.expr.AnnotationExpr;
+import com.github.javaparser.ast.expr.AssignExpr;
+import com.github.javaparser.ast.expr.AssignExpr.Operator;
+import com.github.javaparser.ast.expr.NameExpr;
+import com.github.javaparser.ast.nodeTypes.NodeWithJavadoc;
+import com.github.javaparser.ast.nodeTypes.NodeWithVariables;
+import com.github.javaparser.ast.nodeTypes.modifiers.NodeWithAccessModifiers;
+import com.github.javaparser.ast.nodeTypes.modifiers.NodeWithFinalModifier;
+import com.github.javaparser.ast.nodeTypes.modifiers.NodeWithStaticModifier;
+import com.github.javaparser.ast.observer.ObservableProperty;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.ast.stmt.ReturnStmt;
+import com.github.javaparser.ast.type.Type;
+import com.github.javaparser.ast.type.VoidType;
+import com.github.javaparser.ast.visitor.CloneVisitor;
+import com.github.javaparser.ast.visitor.GenericVisitor;
+import com.github.javaparser.ast.visitor.VoidVisitor;
+import com.github.javaparser.metamodel.FieldDeclarationMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import com.github.javaparser.metamodel.NonEmptyProperty;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Optional;
+import static com.github.javaparser.ast.Modifier.*;
+import static com.github.javaparser.ast.NodeList.nodeList;
+import static com.github.javaparser.utils.Utils.assertNotNull;
+import javax.annotation.Generated;
+import com.github.javaparser.TokenRange;
+import com.github.javaparser.resolution.Resolvable;
+import com.github.javaparser.resolution.declarations.ResolvedConstructorDeclaration;
+import com.github.javaparser.resolution.declarations.ResolvedFieldDeclaration;
+import java.util.function.Consumer;
+
+/**
+ * The declaration of a field in a class. "private static int a=15*15;" in this example: <code>class X { private static
+ * int a=15*15; }</code>
+ *
+ * <br/>All annotations preceding the type will be set on this object, not on the type.
+ * JavaParser doesn't know if it they are applicable to the method or the type.
+ *
+ * @author Julio Vilmar Gesser
+ */
+public final class FieldDeclaration extends BodyDeclaration<FieldDeclaration> implements NodeWithJavadoc<FieldDeclaration>, NodeWithVariables<FieldDeclaration>, NodeWithAccessModifiers<FieldDeclaration>, NodeWithStaticModifier<FieldDeclaration>, NodeWithFinalModifier<FieldDeclaration>, Resolvable<ResolvedFieldDeclaration> {
+
+    private EnumSet<Modifier> modifiers;
+
+    @NonEmptyProperty
+    private NodeList<VariableDeclarator> variables;
+
+    public FieldDeclaration() {
+        this(null, EnumSet.noneOf(Modifier.class), new NodeList<>(), new NodeList<>());
+    }
+
+    public FieldDeclaration(EnumSet<Modifier> modifiers, VariableDeclarator variable) {
+        this(null, modifiers, new NodeList<>(), nodeList(variable));
+    }
+
+    public FieldDeclaration(EnumSet<Modifier> modifiers, NodeList<VariableDeclarator> variables) {
+        this(null, modifiers, new NodeList<>(), variables);
+    }
+
+    @AllFieldsConstructor
+    public FieldDeclaration(EnumSet<Modifier> modifiers, NodeList<AnnotationExpr> annotations, NodeList<VariableDeclarator> variables) {
+        this(null, modifiers, annotations, variables);
+    }
+
+    /**
+     * This constructor is used by the parser and is considered private.
+     */
+    @Generated("com.github.javaparser.generator.core.node.MainConstructorGenerator")
+    public FieldDeclaration(TokenRange tokenRange, EnumSet<Modifier> modifiers, NodeList<AnnotationExpr> annotations, NodeList<VariableDeclarator> variables) {
+        super(tokenRange, annotations);
+        setModifiers(modifiers);
+        setVariables(variables);
+        customInitialization();
+    }
+
+    /**
+     * Creates a {@link FieldDeclaration}.
+     *
+     * @param modifiers modifiers
+     * @param type type
+     * @param name field name
+     */
+    public FieldDeclaration(EnumSet<Modifier> modifiers, Type type, String name) {
+        this(assertNotNull(modifiers), new VariableDeclarator(type, assertNotNull(name)));
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) {
+        return v.visit(this, arg);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
+    public <A> void accept(final VoidVisitor<A> v, final A arg) {
+        v.visit(this, arg);
+    }
+
+    /**
+     * Return the modifiers of this member declaration.
+     *
+     * @return modifiers
+     * @see Modifier
+     */
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public EnumSet<Modifier> getModifiers() {
+        return modifiers;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public NodeList<VariableDeclarator> getVariables() {
+        return variables;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public FieldDeclaration setModifiers(final EnumSet<Modifier> modifiers) {
+        assertNotNull(modifiers);
+        if (modifiers == this.modifiers) {
+            return (FieldDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.MODIFIERS, this.modifiers, modifiers);
+        this.modifiers = modifiers;
+        return this;
+    }
+
+    @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
+    public FieldDeclaration setVariables(final NodeList<VariableDeclarator> variables) {
+        assertNotNull(variables);
+        if (variables == this.variables) {
+            return (FieldDeclaration) this;
+        }
+        notifyPropertyChange(ObservableProperty.VARIABLES, this.variables, variables);
+        if (this.variables != null)
+            this.variables.setParentNode(null);
+        this.variables = variables;
+        setAsParentNodeOf(variables);
+        return this;
+    }
+
+    /**
+     * Create a getter for this field, <b>will only work if this field declares only 1 identifier and if this field is
+     * already added to a ClassOrInterfaceDeclaration</b>
+     *
+     * @return the {@link MethodDeclaration} created
+     * @throws IllegalStateException if there is more than 1 variable identifier or if this field isn't attached to a
+     * class or enum
+     */
+    public MethodDeclaration createGetter() {
+        if (getVariables().size() != 1)
+            throw new IllegalStateException("You can use this only when the field declares only 1 variable name");
+        Optional<ClassOrInterfaceDeclaration> parentClass = getAncestorOfType(ClassOrInterfaceDeclaration.class);
+        Optional<EnumDeclaration> parentEnum = getAncestorOfType(EnumDeclaration.class);
+        if (!(parentClass.isPresent() || parentEnum.isPresent()) || (parentClass.isPresent() && parentClass.get().isInterface()))
+            throw new IllegalStateException("You can use this only when the field is attached to a class or an enum");
+        VariableDeclarator variable = getVariable(0);
+        String fieldName = variable.getNameAsString();
+        String fieldNameUpper = fieldName.toUpperCase().substring(0, 1) + fieldName.substring(1, fieldName.length());
+        final MethodDeclaration getter;
+        getter = parentClass.map(clazz -> clazz.addMethod("get" + fieldNameUpper, PUBLIC)).orElseGet(() -> parentEnum.get().addMethod("get" + fieldNameUpper, PUBLIC));
+        getter.setType(variable.getType());
+        BlockStmt blockStmt = new BlockStmt();
+        getter.setBody(blockStmt);
+        blockStmt.addStatement(new ReturnStmt(fieldName));
+        return getter;
+    }
+
+    /**
+     * Create a setter for this field, <b>will only work if this field declares only 1 identifier and if this field is
+     * already added to a ClassOrInterfaceDeclaration</b>
+     *
+     * @return the {@link MethodDeclaration} created
+     * @throws IllegalStateException if there is more than 1 variable identifier or if this field isn't attached to a
+     * class or enum
+     */
+    public MethodDeclaration createSetter() {
+        if (getVariables().size() != 1)
+            throw new IllegalStateException("You can use this only when the field declares only 1 variable name");
+        Optional<ClassOrInterfaceDeclaration> parentClass = getAncestorOfType(ClassOrInterfaceDeclaration.class);
+        Optional<EnumDeclaration> parentEnum = getAncestorOfType(EnumDeclaration.class);
+        if (!(parentClass.isPresent() || parentEnum.isPresent()) || (parentClass.isPresent() && parentClass.get().isInterface()))
+            throw new IllegalStateException("You can use this only when the field is attached to a class or an enum");
+        VariableDeclarator variable = getVariable(0);
+        String fieldName = variable.getNameAsString();
+        String fieldNameUpper = fieldName.toUpperCase().substring(0, 1) + fieldName.substring(1, fieldName.length());
+        final MethodDeclaration setter;
+        setter = parentClass.map(clazz -> clazz.addMethod("set" + fieldNameUpper, PUBLIC)).orElseGet(() -> parentEnum.get().addMethod("set" + fieldNameUpper, PUBLIC));
+        setter.setType(new VoidType());
+        setter.getParameters().add(new Parameter(variable.getType(), fieldName));
+        BlockStmt blockStmt2 = new BlockStmt();
+        setter.setBody(blockStmt2);
+        blockStmt2.addStatement(new AssignExpr(new NameExpr("this." + fieldName), new NameExpr(fieldName), Operator.ASSIGN));
+        return setter;
+    }
+
+    public boolean isTransient() {
+        return getModifiers().contains(TRANSIENT);
+    }
+
+    public boolean isVolatile() {
+        return getModifiers().contains(VOLATILE);
+    }
+
+    public FieldDeclaration setTransient(boolean set) {
+        return setModifier(TRANSIENT, set);
+    }
+
+    public FieldDeclaration setVolatile(boolean set) {
+        return setModifier(VOLATILE, set);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
+    public boolean remove(Node node) {
+        if (node == null)
+            return false;
+        for (int i = 0; i < variables.size(); i++) {
+            if (variables.get(i) == node) {
+                variables.remove(i);
+                return true;
+            }
+        }
+        return super.remove(node);
+    }
+
+    @Override
+    @Generated("com.github.javaparser.generator.core.node.CloneGenerator")
+    public FieldDeclaration clone() {
+        return (FieldDeclaration) accept(new CloneVisitor(), null);
+    }
+
+    @Override