Snap for 10453938 from 28702590e52bd2e92646a37e82df21825a99ff8c to mainline-odp-release

Change-Id: I023eab15fbd4d65586ca35e7809c97168e6e7efa
diff --git a/.gitignore b/.gitignore
index 79d252b..e3abc30 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,17 @@
-build
+/lib
+out
+/run
+
 .classpath
 .gradle
 .project
 .settings
 *.iml
+
+.DS_Store
+*.swp
+
+.java-version
+
+# Ignore Gradle build output directory
+build
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..216657c
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,2 @@
+!/copyright/
+*
\ No newline at end of file
diff --git a/.idea/copyright/aosp.xml b/.idea/copyright/aosp.xml
new file mode 100644
index 0000000..090509b
--- /dev/null
+++ b/.idea/copyright/aosp.xml
@@ -0,0 +1,6 @@
+<component name="CopyrightManager">
+  <copyright>
+    <option name="notice" value="Copyright (C) &amp;#36;today.year The Android Open Source Project&#10;&#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10;     http://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
+    <option name="myName" value="aosp" />
+  </copyright>
+</component>
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..39c0f13
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,3 @@
+<component name="CopyrightManager">
+  <settings default="aosp" />
+</component>
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 4c81ca5..3bc5dc6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -39,6 +39,7 @@
         "SPDX-license-identifier-CC-BY",
         "SPDX-license-identifier-GPL",
         "SPDX-license-identifier-GPL-2.0",
+        "SPDX-license-identifier-GPL-2.0-with-classpath-exception",
         "SPDX-license-identifier-LGPL",
         "SPDX-license-identifier-MIT",
     ],
@@ -52,38 +53,54 @@
     path: "res/assets/templates-sdk",
 }
 
-java_library_host {
-    name: "doclava",
-    java_version: "1.8",
-    srcs: [
-        "src/**/*.java",
-    ],
+java_defaults {
+    name: "doclava_defaults",
+    java_resource_dirs: ["res"],
+    errorprone: {
+        javacflags: [
+            "-Xep:FormatString:WARN",
+            "-Xep:ComparableType:WARN",
+            "-Xep:ReturnValueIgnored:WARN",
+        ],
+    },
     static_libs: [
         "jsilver",
-        "guava",
         "antlr-runtime",
         "tagsoup",
+        "doclava-doclet-adapter",
     ],
-    use_tools_jar: true,
-    java_resource_dirs: ["res"],
 }
 
 java_library_host {
-    name: "doclava-no-guava",
-    java_version: "1.8",
+    name: "doclava-doclet-adapter",
     srcs: [
-        "src/**/*.java",
+        "doclet_adapter/src/main/java/**/*.java",
     ],
     libs: [
         "guava",
     ],
-    static_libs: [
-        "jsilver",
-        "antlr-runtime",
-        "tagsoup",
+}
+
+java_library_host {
+    name: "doclava",
+    defaults: ["doclava_defaults"],
+    srcs: [
+        "src/com/google/doclava/**/*.java",
     ],
-    use_tools_jar: true,
-    java_resource_dirs: ["res"],
+    static_libs: [
+        "guava",
+    ],
+}
+
+java_library_host {
+    name: "doclava-no-guava",
+    defaults: ["doclava_defaults"],
+    srcs: [
+        "src/com/google/doclava/**/*.java",
+    ],
+    libs: [
+        "guava",
+    ],
 }
 
 
diff --git a/OWNERS b/OWNERS
index dd69424..d91839c 100644
--- a/OWNERS
+++ b/OWNERS
@@ -5,3 +5,10 @@
 ddougherty@google.com
 tiem@google.com
 tnorbye@google.com
+
+# [temporary] some of libcore members involved in
+# Doclava migration to Java 17.
+# See http://b/260694901
+nikitai@google.com #{LAST_RESORT_SUGGESTION}
+oth@google.com #{LAST_RESORT_SUGGESTION}
+sorinbasca@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index 4f586df..0000000
--- a/build.gradle
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * 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.
- */
-
-import javax.tools.ToolProvider
-
-plugins {
-    id("java")
-    id("maven-publish")
-}
-
-group = 'com.android'
-version = '1.0.6'
-
-if (System.env.OUT_DIR != null) {
-    buildDir = file("${System.env.OUT_DIR}/gradle/external/doclava/build").getCanonicalFile()
-} else {
-    buildDir = file('../../out/host/gradle/external/doclava/build')
-}
-
-repositories {
-    maven { url file('../../prebuilts/androidx/external').absolutePath }
-}
-
-dependencies {
-    implementation("org.antlr:antlr:3.5.2")
-    implementation("com.google.jsilver:jsilver:1.0.0")
-    implementation("org.ccil.cowan.tagsoup:tagsoup:1.2.1")
-
-    // tools.jar required for com.sun.javadoc
-    def toolsJar
-    if (JavaVersion.current().getMajorVersion() == "8") {
-        toolsJar = ((URLClassLoader) ToolProvider.getSystemToolClassLoader()).getURLs()
-    } else if (System.env.JAVA_TOOLS_JAR != null) {
-        toolsJar = System.env.JAVA_TOOLS_JAR
-    } else {
-        throw new Exception("If you are not using Java 8, JAVA_TOOLS_JAR env variable " +
-                "needs to be set to tools.jar from a Java 8 installation to build Doclava")
-    }
-    implementation(files(toolsJar))
-
-    testImplementation("junit:junit:4.12")
-}
-
-sourceSets {
-    main {
-        java.srcDirs = ['src/']
-        resources.srcDirs = ['res/']
-    }
-    test {
-        java.srcDirs = ['test/']
-        resources.srcDirs = ['test/api']
-    }
-}
-
-tasks.withType(JavaCompile) {
-    // Suppress build warnings that we're not interested in: b/154755010
-    options.warnings = false
-}
-
-tasks.withType(Jar) { task ->
-    task.reproducibleFileOrder = true
-    task.preserveFileTimestamps = false
-}
diff --git a/build.xml b/build.xml
deleted file mode 100644
index daa6d0d..0000000
--- a/build.xml
+++ /dev/null
@@ -1,106 +0,0 @@
-<project name="doclava" default="jar">
-	<property name="jar.dir" value="build/dist/doclava"/>
-	<property name="jar.file" value="${jar.dir}/doclava.jar"/>
-
-	<property environment="env"/>
-	<property name="javahome" value="${env.JAVA_HOME}" />
-	<property name="jsilver" value="lib/jsilver.jar"/>
-	<property name="junit" value="lib/junit-4.8.2.jar"/>
-	
-	<path id="classpath.test">
-		<pathelement location="${junit}" />
-    <pathelement location="${jar.file}" />
-		<pathelement location="build/test" />
-	</path>
-	
-	<target name="compile" description="Compile Java source.">
-		<mkdir dir="build/classes"/>
-
-		<javac srcdir="src"
-         debug="on"
-         destdir="build/classes"
-         source="1.5"
-         target="1.5"
-         extdirs="">
-			<compilerarg value="-Xlint:all"/>
-			<classpath>
-				<pathelement location="${jsilver}"/>
-			</classpath>
-		</javac>
-	</target>
-
-	<target name="jar" depends="compile" description="Build jar.">
-		<mkdir dir="${jar.dir}"/>
-
-		<copy todir="build/classes/assets">
-			<fileset dir="res/assets"/>
-		</copy>
-
-		<jar jarfile="${jar.file}" manifest="src/MANIFEST.mf">
-			<fileset dir="build/classes"/>
-			<zipfileset src="${jsilver}" />
-		</jar>
-	</target>
-
-	<target name="clean"
-      description="Remove generated files.">
-		<delete dir="build"/>
-	</target>
-
-	<target name="clean-jar" 
-		description="cleans and builds a .jar"
-		depends="clean,jar">
-	</target>
-
-	<target name="compile-test">
-	  <mkdir dir="build/test" />
-		
-		<exec executable="/bin/sh">
-		  <arg value="-c"/>
-		  <arg value="find test/doclava/sample -name '*.java' &gt; build/test/src-list"/>
-		</exec>
-		
-	  <javac srcdir="test" destdir="build/test">
-	  	<classpath refid="classpath.test" />
-	  </javac>
-	</target>
-	
-	<target name="test" depends="jar,compile-test">
-	    <junit>
-	    	<classpath refid="classpath.test" />
-	      <formatter type="brief" usefile="false" />
-
-        <batchtest>
-          <fileset dir="build/test">
-          	<include name="**/*Test.class"/>
-         </fileset>
-        </batchtest>
-	    </junit>
-	 </target>
-
-	<target name="doclava" description="Generate documentation">
-		<taskdef name="doclava" classname="com.google.doclava.DoclavaTask" classpath="${jar.file}"/>
-		
-		 <mkdir dir="build"/>
-		 <exec executable="/bin/sh">
-		   <arg value="-c"/>
-		   <arg value="find ./src -name '*.java' &gt; build/src-list"/>
-		 </exec>
-			
-			
-		<doclava>
-			<arguments>
-	        	-quiet
-	        	-bootclasspath "${javahome}/jre/lib/rt.jar"
-	        	-doclet com.google.doclava.Doclava
-	        	-docletpath ${jar.file}
-	        	-classpath ${jar.file}
-	        	-d build/api
-	 	       	-hdf project.name "Junction"
-	        	-stubs build/stubs
-	        	-apixml build/public_api.xml
-	        	@build/src-list
-	      	</arguments>
-		</doclava>
-	</target>
-</project>
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
new file mode 100644
index 0000000..70dc291
--- /dev/null
+++ b/buildSrc/build.gradle.kts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+plugins {
+    // Support convention plugins written in Kotlin. Convention plugins are build scripts in 'src/main' that automatically become available as plugins in the main build.
+    `kotlin-dsl`
+}
+
+repositories {
+    // Use the plugin portal to apply community plugins in convention plugins.
+    gradlePluginPortal()
+}
diff --git a/buildSrc/src/main/kotlin/com.google.doclava.java-application-conventions.gradle.kts b/buildSrc/src/main/kotlin/com.google.doclava.java-application-conventions.gradle.kts
new file mode 100644
index 0000000..2a3eb48
--- /dev/null
+++ b/buildSrc/src/main/kotlin/com.google.doclava.java-application-conventions.gradle.kts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+plugins {
+    // Apply the common convention plugin for shared build configuration between library and application projects.
+    id("com.google.doclava.java-common-conventions")
+
+    // Apply the application plugin to add support for building a CLI application in Java.
+    application
+}
+
+application {
+    mainClass.set("com.google.doclava.Doclava")
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/com.google.doclava.java-common-conventions.gradle.kts b/buildSrc/src/main/kotlin/com.google.doclava.java-common-conventions.gradle.kts
new file mode 100644
index 0000000..9e2167b
--- /dev/null
+++ b/buildSrc/src/main/kotlin/com.google.doclava.java-common-conventions.gradle.kts
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+plugins {
+    // Apply the java Plugin to add support for Java.
+    java
+}
+
+repositories {
+    mavenCentral()
+    google()
+}
+
+dependencies {
+    implementation("org.antlr:antlr:3.5.2")
+    implementation("com.google.jsilver:jsilver:1.0.0")
+    implementation("org.ccil.cowan.tagsoup:tagsoup:1.2.1")
+
+    testImplementation("org.junit.jupiter:junit-jupiter:5.7.1")
+    testCompileOnly("junit:junit:4.13.2")
+    testRuntimeOnly("org.junit.vintage:junit-vintage-engine")
+}
+
+tasks.named<Test>("test") {
+    useJUnitPlatform {
+        includeEngines("junit-vintage")
+    }
+}
+
+tasks.withType<JavaCompile>() {
+    options.isWarnings = false
+}
diff --git a/settings.gradle b/buildSrc/src/main/kotlin/com.google.doclava.java-library-conventions.gradle.kts
similarity index 62%
copy from settings.gradle
copy to buildSrc/src/main/kotlin/com.google.doclava.java-library-conventions.gradle.kts
index c6b98ee..8559704 100644
--- a/settings.gradle
+++ b/buildSrc/src/main/kotlin/com.google.doclava.java-library-conventions.gradle.kts
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,10 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+plugins {
+    // Apply the common convention plugin for shared build configuration between library and application projects.
+    id("com.google.doclava.java-common-conventions")
+
+    // Apply the java-library plugin for API and implementation separation.
+    `java-library`
+}
diff --git a/doclet_adapter/build.gradle.kts b/doclet_adapter/build.gradle.kts
new file mode 100644
index 0000000..855d430
--- /dev/null
+++ b/doclet_adapter/build.gradle.kts
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+plugins {
+    id("com.google.doclava.java-application-conventions")
+}
+
+java {
+    toolchain {
+        languageVersion.set(JavaLanguageVersion.of(17))
+    }
+}
+
+dependencies {
+    implementation("com.google.code.findbugs:jsr305:3.0.2")
+}
+
+sourceSets {
+    main {
+        java {
+            srcDir("${project.rootDir}/src")
+        }
+        resources {
+            srcDirs("${project.rootDir}/res")
+        }
+    }
+}
+
+val addedExports = listOf("--add-exports", "jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED")
+
+tasks.withType<JavaCompile> {
+    options.compilerArgs.addAll(addedExports)
+
+    // Exporting a package from system module jdk.javadoc is not allowed with --release so
+    // trick gradle to use -source/-target flags instead.
+    sourceCompatibility = JavaVersion.VERSION_17.majorVersion
+}
+
+tasks.withType<Test> {
+    jvmArgs(addedExports)
+}
+
+val docletJars by configurations.creating {
+    extendsFrom(configurations.runtimeClasspath.get())
+}
+
+tasks.javadoc {
+    dependsOn("e2eTestAOSP")
+}
+
+tasks.create<Exec>("e2eTestAOSP") {
+    dependsOn("jar")
+
+    val outputDirectory = project.buildDir.resolve("docs/aosp")
+    val docletpath = listOf(
+        buildDir.resolve("libs/${project.name}.jar").absolutePath,
+        *docletJars.files.map { it.path }.toTypedArray(),
+    ).joinToString(separator = ":")
+
+    group = "run"
+    workingDir = rootProject.rootDir.resolve("run")
+    outputs.dir(outputDirectory)
+    outputs.upToDateWhen {
+        !tasks.getByPath("jar").didWork
+    }
+
+    val javadocTool = javaToolchains.javadocToolFor {
+        languageVersion.set(JavaLanguageVersion.of(17))
+    }.get().executablePath.toString()
+
+    val args = mutableListOf(
+        javadocTool,
+        "-d",
+        outputDirectory.absolutePath,
+        "-doclet",
+        application.mainClass.get(),
+        "-docletpath",
+        docletpath,
+        "-encoding", "UTF-8",
+        "-sourcepath", "out/soong/.intermediates/frameworks/base/offline-sdk-docs/android_common/srcjars", "@out/soong/.intermediates/frameworks/base/offline-sdk-docs/android_common/javadoc.rsp", "@out/soong/.intermediates/frameworks/base/offline-sdk-docs/android_common/srcjars/list",
+        "-bootclasspath", "out/soong/.intermediates/build/soong/java/core-libraries/stable.core.platform.api.stubs/android_common/combined/stable.core.platform.api.stubs.jar:out/soong/.intermediates/libcore/core-lambda-stubs/android_common/javac/core-lambda-stubs.jar",
+        "-classpath", "out/soong/.intermediates/frameworks/base/ext/android_common/turbine-combined/ext.jar:out/soong/.intermediates/frameworks/base/framework/android_common/turbine-combined/framework.jar:out/soong/.intermediates/frameworks/opt/net/voip/voip-common/android_common/turbine-combined/voip-common.jar:out/soong/.intermediates/frameworks/base/test-mock/android.test.mock.stubs.system/android_common/turbine-combined/android.test.mock.stubs.system.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-annotations/android_common/turbine-combined/android-support-annotations.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-compat/android_common/turbine-combined/android-support-compat.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-core-ui/android_common/turbine-combined/android-support-core-ui.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-core-utils/android_common/turbine-combined/android-support-core-utils.jar:out/soong/.intermediates/prebuilts/sdk/current/extras/material-design/android-support-design/android_common/turbine-combined/android-support-design.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-dynamic-animation/android_common/turbine-combined/android-support-dynamic-animation.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-exifinterface/android_common/turbine-combined/android-support-exifinterface.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-fragment/android_common/turbine-combined/android-support-fragment.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-media-compat/android_common/turbine-combined/android-support-media-compat.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-percent/android_common/turbine-combined/android-support-percent.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-transition/android_common/turbine-combined/android-support-transition.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-v7-cardview/android_common/turbine-combined/android-support-v7-cardview.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-v7-gridlayout/android_common/turbine-combined/android-support-v7-gridlayout.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-v7-mediarouter/android_common/turbine-combined/android-support-v7-mediarouter.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-v7-palette/android_common/turbine-combined/android-support-v7-palette.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-v7-preference/android_common/turbine-combined/android-support-v7-preference.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-v13/android_common/turbine-combined/android-support-v13.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-v14-preference/android_common/turbine-combined/android-support-v14-preference.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-v17-leanback/android_common/turbine-combined/android-support-v17-leanback.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-vectordrawable/android_common/turbine-combined/android-support-vectordrawable.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-animatedvectordrawable/android_common/turbine-combined/android-support-animatedvectordrawable.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-v7-appcompat/android_common/turbine-combined/android-support-v7-appcompat.jar:out/soong/.intermediates/prebuilts/sdk/current/support/android-support-v7-recyclerview/android_common/turbine-combined/android-support-v7-recyclerview.jar:out/soong/.intermediates/frameworks/rs/support/android-support-v8-renderscript/android_common/turbine-combined/android-support-v8-renderscript.jar:out/soong/.intermediates/frameworks/multidex/library/android-support-multidex/android_common/turbine-combined/android-support-multidex.jar:out/soong/.intermediates/frameworks/multidex/instrumentation/android-support-multidex-instrumentation/android_common/turbine-combined/android-support-multidex-instrumentation.jar:out/soong/.intermediates/tools/metalava/stub-annotations/android_common/turbine-combined/stub-annotations.jar:out/soong/.intermediates/tools/platform-compat/java/android/compat/annotation/unsupportedappusage/android_common/turbine-combined/unsupportedappusage.jar:out/soong/.intermediates/prebuilts/runtime/mainline/i18n/sdk/core-icu4j/android_common/combined/core-icu4j.jar",
+        "-android",
+        "-manifest", "frameworks_base_core_res_AndroidManifest.xml",
+        "-hide", "111",
+        "-hide", "113",
+        "-hide", "125",
+        "-hide", "126",
+        "-hide", "127",
+        "-hide", "128",
+        "-overview", "frameworks_base_core_java_overview.html",
+        "-federate", "SupportLib", "https://developer.android.com",
+        "-federationapi", "SupportLib", "prebuilts_sdk_current_support-api.txt",
+        "-federate", "AndroidX", "https://developer.android.com",
+        "-federationapi", "AndroidX", "prebuilts_sdk_current_androidx-api.txt",
+        "-offlinemode",
+        "-title", "Android SDK",
+        "-compatconfig", "out/soong/.intermediates/tools/platform-compat/build/global-compat-config/android_common/all_compat_config.xml",
+        "-source", "1.8",
+        "-J-Xmx1600m",
+        "-XDignore.symbol.file",
+        "-hdf", "page.build", "AOSP.MASTER-nikitai-doclava17",
+        "-hdf", "page.now", "Wed Feb  1 20:27:46 GMT 2023",
+        "-templatedir", "../res/assets/templates-sdk",
+        "-htmldir", "frameworks_base_docs/html",
+        "-knowntags", "frameworks_base_docs/knowntags.txt",
+        "-knowntags", "libcore_known_oj_tags.txt",
+        "-hdf", "dac", "true",
+        "-hdf", "sdk.codename", "O",
+        "-hdf", "sdk.preview.version", "1",
+        "-hdf", "sdk.version", "7.0",
+        "-hdf", "sdk.rel.id", "1",
+        "-hdf", "sdk.preview", "0",
+        "-hdf", "android.whichdoc", "offline",
+        "-proofread", "out/soong/.intermediates/frameworks/base/offline-sdk-docs/android_common/offline-sdk-docs-proofread.txt",
+        "-resourcesdir", "frameworks_base_docs/html/reference/images",
+        "-resourcesoutdir", "reference/android/images/",
+        // parameters to tweak
+        //"-werror",
+        //"-lerror",
+        if (false) "-verbose" else "-quiet"
+    )
+    commandLine = args
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/annotation/Unused.java b/doclet_adapter/src/main/java/com/google/doclava/annotation/Unused.java
new file mode 100644
index 0000000..f2dbc75
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/annotation/Unused.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that a method declaration is <b>not required</b> for Doclava to work and <b>does
+ * not</b> have to be implemented.
+ * <p>
+ * The parameter {@code implemented} declares that a method has been implemented, i.e. does not
+ * throw {@link UnsupportedOperationException} which is used as a default implementation.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.SOURCE)
+public @interface Unused {
+
+    boolean implemented() default false;
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/annotation/Used.java b/doclet_adapter/src/main/java/com/google/doclava/annotation/Used.java
new file mode 100644
index 0000000..ac4550c
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/annotation/Used.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that a method declaration is required for Doclava to work and has to be implemented.
+ * <p>
+ * The parameter {@code implemented} declares that a method has been implemented, i.e. does not
+ * throw {@link UnsupportedOperationException} which is used as a default implementation.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.SOURCE)
+public @interface Used {
+
+    boolean implemented() default false;
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/AnnotatedTypeImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/AnnotatedTypeImpl.java
new file mode 100644
index 0000000..436b1f8
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/AnnotatedTypeImpl.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.AnnotatedType;
+import com.sun.javadoc.AnnotationDesc;
+import com.sun.javadoc.AnnotationTypeDoc;
+import com.sun.javadoc.Type;
+import javax.lang.model.type.DeclaredType;
+
+class AnnotatedTypeImpl extends TypeImpl implements AnnotatedType {
+
+    private final DeclaredType declaredType;
+
+    private Type underlyingType;
+
+    private AnnotationDesc[] annotations;
+
+    protected AnnotatedTypeImpl(DeclaredType declaredType, Context context) {
+        super(declaredType, context);
+        this.declaredType = declaredType;
+    }
+
+    static AnnotatedTypeImpl create(DeclaredType declaredType, Context context) {
+        return context.caches.types.annotated.computeIfAbsent(declaredType,
+                el -> new AnnotatedTypeImpl(el, context));
+    }
+
+    /**
+     * @return annotations
+     * @implNote Implemented as used in {@code ParameterImplTests#annotations()}.
+     */
+    @Override
+    @Unused(implemented = true)
+    public AnnotationDesc[] annotations() {
+        if (annotations == null) {
+            annotations = declaredType.getAnnotationMirrors()
+                    .stream()
+                    .map(am -> new AnnotationDescImpl(am, context))
+                    .toArray(AnnotationDescImpl[]::new);
+        }
+        return annotations;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public Type underlyingType() {
+        if (underlyingType == null) {
+            underlyingType = TypeImpl.create(declaredType, context, /* underlyingType= */ true);
+        }
+        return underlyingType;
+    }
+
+    @Override
+    public AnnotatedType asAnnotatedType() {
+        return this;
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/AnnotationDescImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/AnnotationDescImpl.java
new file mode 100644
index 0000000..dcb8695
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/AnnotationDescImpl.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.AnnotationDesc;
+import com.sun.javadoc.AnnotationTypeDoc;
+import com.sun.javadoc.AnnotationTypeElementDoc;
+import com.sun.javadoc.AnnotationValue;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.TypeElement;
+
+class AnnotationDescImpl implements AnnotationDesc {
+
+    private final AnnotationTypeDocImpl annotationType;
+    private final ElementValuePairImpl[] elementValues;
+
+    public AnnotationDescImpl(AnnotationMirror mirror, Context context) {
+        this.annotationType = AnnotationTypeDocImpl.create(
+                (TypeElement) mirror.getAnnotationType().asElement(), context);
+        this.elementValues = mirror.getElementValues()
+                .entrySet()
+                .stream()
+                .map(kv -> {
+                    var element = AnnotationMethodDocImpl.create(kv.getKey(), context);
+                    var value = AnnotationValueImpl.create(kv.getValue(), context);
+                    return new ElementValuePairImpl(element, value);
+                })
+                .toArray(ElementValuePairImpl[]::new);
+    }
+
+    @Override
+    @Used(implemented = true)
+    public AnnotationTypeDoc annotationType() {
+        return annotationType;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ElementValuePair[] elementValues() {
+        return elementValues;
+    }
+
+    @Override
+    @Unused
+    public boolean isSynthesized() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    static class ElementValuePairImpl implements ElementValuePair {
+
+        private final AnnotationMethodDocImpl element;
+        private final AnnotationValueImpl value;
+
+        public ElementValuePairImpl(AnnotationMethodDocImpl element, AnnotationValueImpl value) {
+            this.element = element;
+            this.value = value;
+        }
+
+        @Override
+        @Used(implemented = true)
+        public AnnotationTypeElementDoc element() {
+            return element;
+        }
+
+        @Override
+        @Used(implemented = true)
+        public AnnotationValue value() {
+            return value;
+        }
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/AnnotationMethodDocImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/AnnotationMethodDocImpl.java
new file mode 100644
index 0000000..8e3813c
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/AnnotationMethodDocImpl.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.AnnotationTypeElementDoc;
+import com.sun.javadoc.AnnotationValue;
+import javax.lang.model.element.ExecutableElement;
+
+/**
+ * In a nutshell, represents a method of an annotation.
+ */
+class AnnotationMethodDocImpl extends MethodDocImpl implements AnnotationTypeElementDoc {
+
+    protected AnnotationValueImpl defaultValue;
+
+    protected AnnotationMethodDocImpl(ExecutableElement e, Context context) {
+        super(e, context);
+        defaultValue = AnnotationValueImpl.create(e.getDefaultValue(), context);
+    }
+
+    static AnnotationMethodDocImpl create(ExecutableElement e, Context context) {
+        return context.caches.annotationMethods.computeIfAbsent(e,
+                el -> new AnnotationMethodDocImpl(el, context));
+    }
+
+    @Override
+    @Used(implemented = true)
+    public AnnotationValue defaultValue() {
+        return defaultValue;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isAnnotationTypeElement() {
+        return true;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isMethod() {
+        return false;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isAbstract() {
+        return false;
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/AnnotationTypeDocImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/AnnotationTypeDocImpl.java
new file mode 100644
index 0000000..58bfdfe
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/AnnotationTypeDocImpl.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.AnnotationTypeDoc;
+import com.sun.javadoc.AnnotationTypeElementDoc;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
+
+class AnnotationTypeDocImpl extends ClassDocImpl implements AnnotationTypeDoc {
+
+    protected AnnotationTypeDocImpl(TypeElement c, Context context) {
+        super(c, context);
+    }
+
+    // Cached fields
+    private AnnotationTypeElementDoc[] elements;
+
+    static AnnotationTypeDocImpl create(TypeElement e, Context context) {
+        if (e.getKind() != ElementKind.ANNOTATION_TYPE) {
+            throw new IllegalArgumentException("Expected ElementKind.ANNOTATION_TYPE as first "
+                    + "argument, but got " + e.getKind());
+        }
+        return context.caches.annotations.computeIfAbsent(e, el -> new AnnotationTypeDocImpl(el,
+                context));
+    }
+
+    @Override
+    @Used(implemented = true)
+    public AnnotationTypeElementDoc[] elements() {
+        if (elements == null) {
+            elements = ElementFilter.methodsIn(typeElement.getEnclosedElements())
+                    .stream()
+                    .map(exe -> AnnotationMethodDocImpl.create(exe, context))
+                    .toArray(AnnotationTypeElementDoc[]::new);
+        }
+        return elements;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isAnnotationType() {
+        return true;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isInterface() {
+        return false;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public AnnotationTypeDoc asAnnotationTypeDoc() {
+        return this;
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/AnnotationValueImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/AnnotationValueImpl.java
new file mode 100644
index 0000000..e3ea5d0
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/AnnotationValueImpl.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.AnnotationValue;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleAnnotationValueVisitor14;
+
+class AnnotationValueImpl implements AnnotationValue {
+
+    protected final javax.lang.model.element.AnnotationValue annotationValue;
+    protected final Context context;
+
+    protected AnnotationValueImpl(@Nonnull javax.lang.model.element.AnnotationValue av,
+            Context context) {
+        this.context = context;
+        annotationValue = av;
+    }
+
+    public static @Nullable
+    AnnotationValueImpl create(@Nullable javax.lang.model.element.AnnotationValue av,
+            Context context) {
+        // av could be null if it's a result of ExecutableElement#getDefaultValue()
+        if (av == null) {
+            return null;
+        }
+        return context.caches.annotationValues.computeIfAbsent(av,
+                el -> new AnnotationValueImpl(el, context));
+    }
+
+    private Object value;
+
+    @Override
+    @Used(implemented = true)
+    public Object value() {
+        if (value == null) {
+            value = valueVisitor.visit(annotationValue, context);
+        }
+        return value;
+    }
+
+    private static final SimpleAnnotationValueVisitor14<Object, Context> valueVisitor =
+            new SimpleAnnotationValueVisitor14<>() {
+                @Override
+                public Object visitBoolean(boolean b, Context ctx) {
+                    return b;
+                }
+
+                @Override
+                public Object visitByte(byte b, Context ctx) {
+                    return b;
+                }
+
+                @Override
+                public Object visitChar(char c, Context ctx) {
+                    return c;
+                }
+
+                @Override
+                public Object visitDouble(double d, Context ctx) {
+                    return d;
+                }
+
+                @Override
+                public Object visitFloat(float f, Context ctx) {
+                    return f;
+                }
+
+                @Override
+                public Object visitInt(int i, Context ctx) {
+                    return i;
+                }
+
+                @Override
+                public Object visitLong(long l, Context ctx) {
+                    return l;
+                }
+
+                @Override
+                public Object visitShort(short s, Context ctx) {
+                    return s;
+                }
+
+                @Override
+                public Object visitString(String s, Context ctx) {
+                    return s;
+                }
+
+                @Override
+                public Object visitType(TypeMirror m, Context ctx) {
+                    var e = ctx.environment.getTypeUtils().asElement(m);
+                    return switch (e.getKind()) {
+                        case CLASS, INTERFACE, ENUM -> ClassDocImpl.create((TypeElement) e, ctx);
+                        case ANNOTATION_TYPE -> AnnotationTypeDocImpl.create((TypeElement) e, ctx);
+                        default -> throw new UnsupportedOperationException(
+                                e.getKind() + " is not not yet implemented");
+                    };
+                }
+
+                @Override
+                public Object visitEnumConstant(VariableElement c, Context context) {
+                    return null;
+                }
+
+                @Override
+                public Object visitAnnotation(AnnotationMirror m, Context ctx) {
+                    return null;
+                }
+
+                @Override
+                public Object visitArray(
+                        List<? extends javax.lang.model.element.AnnotationValue> vals,
+                        Context ctx) {
+                    AnnotationValueImpl[] ret = new AnnotationValueImpl[vals.size()];
+                    for (int i = 0; i < vals.size(); i++) {
+                        ret[i] = AnnotationValueImpl.create(vals.get(i), ctx);
+                    }
+                    return ret;
+                }
+
+                @Override
+                protected Object defaultAction(Object o, Context context) {
+                    throw new UnsupportedOperationException("Unexpected annotation value: " + o);
+                }
+            };
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/ArrayTypeImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ArrayTypeImpl.java
new file mode 100644
index 0000000..b7ba0a1
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ArrayTypeImpl.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.AnnotationTypeDoc;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.ParameterizedType;
+import com.sun.javadoc.Type;
+import com.sun.javadoc.TypeVariable;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+public final class ArrayTypeImpl extends TypeImpl {
+
+    private final ArrayType arrayType;
+    private final Type underlyingType;
+    private final String dimension;
+
+    private ArrayTypeImpl(ArrayType at, Context context) {
+        super(at, context);
+        arrayType = at;
+
+        int dim = 0;
+        TypeMirror cur = at;
+        while (cur.getKind() == TypeKind.ARRAY) {
+            dim++;
+            cur = ((ArrayType) cur).getComponentType();
+        }
+        dimension = "[]".repeat(dim);
+        underlyingType = TypeImpl.create(cur, context);
+    }
+
+    public static ArrayTypeImpl create(ArrayType at, Context context) {
+        return context.caches.types.array.computeIfAbsent(at, x -> new ArrayTypeImpl(x, context));
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String qualifiedTypeName() {
+        return underlyingType.qualifiedTypeName();
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String simpleTypeName() {
+        return underlyingType.simpleTypeName();
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String dimension() {
+        return dimension;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc asClassDoc() {
+        return underlyingType.asClassDoc();
+    }
+
+    @Override
+    @Used(implemented = true)
+    public TypeVariable asTypeVariable() {
+        return underlyingType.asTypeVariable();
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ParameterizedType asParameterizedType() {
+        return underlyingType.asParameterizedType();
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public AnnotationTypeDoc asAnnotationTypeDoc() {
+        return underlyingType.asAnnotationTypeDoc();
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isPrimitive() {
+        return underlyingType.isPrimitive();
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/ClassDocImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ClassDocImpl.java
new file mode 100644
index 0000000..0b6ec3e
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ClassDocImpl.java
@@ -0,0 +1,626 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.AnnotatedType;
+import com.sun.javadoc.AnnotationTypeDoc;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.ConstructorDoc;
+import com.sun.javadoc.FieldDoc;
+import com.sun.javadoc.MethodDoc;
+import com.sun.javadoc.PackageDoc;
+import com.sun.javadoc.ParamTag;
+import com.sun.javadoc.ParameterizedType;
+import com.sun.javadoc.Type;
+import com.sun.javadoc.TypeVariable;
+import com.sun.javadoc.WildcardType;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.NestingKind;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+
+class ClassDocImpl extends ProgramElementDocImpl<TypeElement> implements ClassDoc {
+
+    protected final TypeElement typeElement;
+
+    // Cached fields
+    private ConstructorDoc[] constructorsFiltered;
+    private ConstructorDoc[] constructorsAll;
+    private Type[] interfaceTypes;
+    private ClassDoc[] interfaces;
+    private TypeVariable[] typeParameters;
+    private MethodDoc[] methodsFiltered;
+    private MethodDoc[] methodsAll;
+    private FieldDoc[] fieldsFiltered;
+    private FieldDoc[] fieldsAll;
+    private FieldDoc[] enumConstants;
+    private ClassDoc[] innerClassesFiltered;
+    private ClassDoc[] innerClassesAll;
+
+    protected ClassDocImpl(TypeElement c, Context context) {
+        super(c, context);
+        typeElement = c;
+
+        if (c.getKind().isInterface()) {
+            reflectModifiers |= java.lang.reflect.Modifier.INTERFACE;
+        }
+    }
+
+    static ClassDocImpl create(TypeElement e, Context context) {
+        return context.caches.classes.computeIfAbsent(e, el -> new ClassDocImpl(el, context));
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public String modifiers() {
+        return java.lang.reflect.Modifier.toString(modifierSpecifier());
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public int modifierSpecifier() {
+        if (isInterface() || isAnnotationType()) {
+            return reflectModifiers & ~java.lang.reflect.Modifier.ABSTRACT;
+        }
+        return reflectModifiers;
+    }
+
+    private Boolean isClass;
+
+    @Override
+    @Unused(implemented = true)
+    public boolean isClass() {
+        if (isClass == null) {
+            isClass = typeElement.getKind().isClass();
+        }
+        return isClass;
+    }
+
+    private Boolean isOrdinaryClass;
+
+    @Override
+    @Used(implemented = true)
+    public boolean isOrdinaryClass() {
+        if (isOrdinaryClass == null) {
+            isOrdinaryClass = (!isEnum() &&
+                    !isInterface() &&
+                    !isAnnotationType() &&
+                    !isError() &&
+                    !isException()
+            );
+        }
+        return isOrdinaryClass;
+    }
+
+    private Boolean isEnum;
+
+    @Override
+    @Used(implemented = true)
+    public boolean isEnum() {
+        if (isEnum == null) {
+            isEnum = (typeElement.getKind() == ElementKind.ENUM);
+        }
+        return isEnum;
+    }
+
+    private Boolean isInterface;
+
+    @Override
+    @Used(implemented = true)
+    public boolean isInterface() {
+        if (isInterface == null) {
+            isInterface = (typeElement.getKind() == ElementKind.INTERFACE);
+        }
+        return isInterface;
+    }
+
+    private Boolean isException;
+
+    @Override
+    @Used(implemented = true)
+    public boolean isException() {
+        if (isException == null) {
+            isException = context.docletElementUtils.isException(typeElement);
+        }
+        return isException;
+    }
+
+    private Boolean isError;
+
+    @Override
+    @Used(implemented = true)
+    public boolean isError() {
+        if (isError == null) {
+            isError = context.docletElementUtils.isError(typeElement);
+        }
+        return isError;
+    }
+
+    private String name;
+
+    @Override
+    @Used(implemented = true)
+    public String name() {
+        if (name == null) {
+            name = context.docletElementUtils.getClassNameUntilNotNested(typeElement);
+        }
+        return name;
+    }
+
+    private String qualifiedName;
+
+    @Override
+    @Used(implemented = true)
+    public String qualifiedName() {
+        if (qualifiedName == null) {
+            qualifiedName = typeElement.getQualifiedName().toString();
+        }
+        return qualifiedName;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isIncluded() {
+        return context.environment.isIncluded(typeElement);
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isAbstract() {
+        return java.lang.reflect.Modifier.isAbstract(reflectModifiers);
+    }
+
+    private Boolean isSerializable;
+
+    @Override
+    @Used(implemented = true)
+    public boolean isSerializable() {
+        if (isSerializable == null) {
+            var serializable = context.environment.getElementUtils()
+                    .getTypeElement("java.io.Serializable").asType();
+            isSerializable = context.environment.getTypeUtils()
+                    .isSubtype(typeElement.asType(), serializable);
+        }
+        return isSerializable;
+    }
+
+    private Boolean isExternalizable;
+
+    @Override
+    @Unused(implemented = true)
+    public boolean isExternalizable() {
+        if (isExternalizable == null) {
+            var externalizable = context.environment.getElementUtils()
+                    .getTypeElement("java.io.Externalizable").asType();
+            isExternalizable = context.environment.getTypeUtils()
+                    .isSubtype(typeElement.asType(), externalizable);
+        }
+        return isExternalizable;
+    }
+
+    @Override
+    @Unused
+    public MethodDoc[] serializationMethods() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused
+    public FieldDoc[] serializableFields() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused
+    public boolean definesSerializableFields() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc superclass() {
+        if (isInterface()) {
+            return null;
+        }
+        TypeMirror superclassMirror = typeElement.getSuperclass();
+        if (superclassMirror.getKind() == TypeKind.NONE) {
+            return null;
+        }
+        return TypeImpl.create(superclassMirror, context).asClassDoc();
+    }
+
+    @Override
+    @Used(implemented = true)
+    public Type superclassType() {
+        if (isInterface()) {
+            return null;
+        }
+        TypeMirror superclassMirror = typeElement.getSuperclass();
+        if (superclassMirror.getKind() == TypeKind.NONE) {
+            return null;
+        }
+        return TypeImpl.create(superclassMirror, context);
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public boolean subclassOf(ClassDoc cd) {
+        TypeElement other = context.environment.getElementUtils()
+                .getTypeElement(cd.qualifiedName());
+        if (isInterface()) {
+            return other.getQualifiedName().contentEquals("java.lang.Object");
+        }
+        return context.environment.getTypeUtils().isSubtype(typeElement.asType(), other.asType());
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc[] interfaces() {
+        if (interfaces == null) {
+            interfaces = typeElement.getInterfaces()
+                    .stream()
+                    .map(typeMirror -> {
+                        TypeElement asElement = (TypeElement) context.environment.getTypeUtils()
+                                .asElement(typeMirror);
+                        return ClassDocImpl.create(asElement, context);
+                    })
+                    .toArray(ClassDoc[]::new);
+        }
+        return interfaces;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public Type[] interfaceTypes() {
+        if (interfaceTypes == null) {
+            interfaceTypes = typeElement.getInterfaces()
+                    .stream()
+                    .filter(typeMirror -> !typeMirror.getKind().equals(TypeKind.NONE))
+                    .map(typeMirror -> TypeImpl.create(typeMirror, context))
+                    .toArray(Type[]::new);
+        }
+        return interfaceTypes;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public TypeVariable[] typeParameters() {
+        if (typeParameters == null) {
+            typeParameters = typeElement.getTypeParameters()
+                    .stream()
+                    .map(tp -> {
+                        javax.lang.model.type.TypeVariable tv = (javax.lang.model.type.TypeVariable) tp.asType();
+                        return TypeVariableImpl.create(tv, context);
+                    })
+                    .toArray(TypeVariable[]::new);
+        }
+        return typeParameters;
+    }
+
+    @Override
+    @Unused
+    public ParamTag[] typeParamTags() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public FieldDoc[] fields() {
+        if (fieldsAll == null) {
+            fieldsAll = getFields(true);
+        }
+        return fieldsAll;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public FieldDoc[] fields(boolean filter) {
+        if (filter) {
+            if (fieldsFiltered == null) {
+                fieldsFiltered = getFields(true);
+            }
+            return fieldsFiltered;
+        } else {
+            if (fieldsAll == null) {
+                fieldsAll = getFields(false);
+            }
+            return fieldsAll;
+        }
+    }
+
+    private FieldDoc[] getFields(boolean filter) {
+        return typeElement.getEnclosedElements()
+                .stream()
+                .filter(e -> e.getKind() == ElementKind.FIELD)
+                .filter(field -> !filter || context.environment.isSelected(field))
+                .map(field -> FieldDocImpl.create((VariableElement) field, context))
+                .toArray(FieldDoc[]::new);
+    }
+
+    @Override
+    @Used(implemented = true)
+    public FieldDoc[] enumConstants() {
+        if (enumConstants == null) {
+            enumConstants = typeElement.getEnclosedElements()
+                    .stream()
+                    .filter(e -> e.getKind() == ElementKind.ENUM_CONSTANT)
+                    .map(enumConstant -> FieldDocImpl.create((VariableElement) enumConstant,
+                            context))
+                    .toArray(FieldDoc[]::new);
+        }
+        return enumConstants;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public MethodDoc[] methods() {
+        if (methodsAll == null) {
+            methodsAll = getMethods(true);
+        }
+        return methodsAll;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public MethodDoc[] methods(boolean filter) {
+        if (filter) {
+            if (methodsFiltered == null) {
+                methodsFiltered = getMethods(true);
+            }
+            return methodsFiltered;
+        } else {
+            if (methodsAll == null) {
+                methodsAll = getMethods(false);
+            }
+            return methodsAll;
+        }
+    }
+
+    private MethodDoc[] getMethods(boolean filter) {
+        return typeElement.getEnclosedElements()
+                .stream()
+                .filter(e -> e.getKind() == ElementKind.METHOD)
+                .filter(method -> !filter || context.environment.isSelected(method))
+                .map(method -> MethodDocImpl.create((ExecutableElement) method, context))
+                .toArray(MethodDoc[]::new);
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public ConstructorDoc[] constructors() {
+        if (constructorsFiltered == null) {
+            constructorsFiltered = getConstructors(true);
+        }
+        return constructorsFiltered;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ConstructorDoc[] constructors(boolean filter) {
+        if (filter) {
+            if (constructorsFiltered == null) {
+                constructorsFiltered = getConstructors(true);
+            }
+            return constructorsFiltered;
+        } else {
+            if (constructorsAll == null) {
+                constructorsAll = getConstructors(false);
+            }
+            return constructorsAll;
+        }
+    }
+
+    private ConstructorDoc[] getConstructors(boolean filter) {
+        return typeElement.getEnclosedElements()
+                .stream()
+                .filter(e -> e.getKind() == ElementKind.CONSTRUCTOR)
+                .filter(ctor -> !filter || context.environment.isSelected(ctor))
+                .map(e -> ConstructorDocImpl.create((ExecutableElement) e, context))
+                .toArray(ConstructorDoc[]::new);
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc[] innerClasses() {
+        if (innerClassesFiltered == null) {
+            innerClassesFiltered = getInnerClasses(true);
+        }
+        return innerClassesFiltered;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc[] innerClasses(boolean filter) {
+        if (filter) {
+            return innerClasses();
+        } else {
+            if (innerClassesAll == null) {
+                innerClassesAll = getInnerClasses(false);
+            }
+            return innerClassesAll;
+        }
+    }
+
+    private ClassDoc[] getInnerClasses(boolean filter) {
+        return ElementFilter.typesIn(typeElement.getEnclosedElements())
+                .stream()
+                .filter(te -> te.getNestingKind() == NestingKind.MEMBER &&
+                        (te.getKind() == ElementKind.CLASS || te.getKind() == ElementKind.INTERFACE)
+                )
+                .filter(te -> !filter || context.environment.isSelected(te))
+                .map(te -> ClassDocImpl.create(te, context))
+                .toArray(ClassDoc[]::new);
+    }
+
+    /**
+     * Note that this implementation does not search in sources!
+     *
+     * <p>
+     *
+     * {@inheritDoc}
+     *
+     * @implNote Does not search in sources.
+     */
+    @Override
+    @Used(implemented = true)
+    public ClassDoc findClass(String className) {
+        ClassDoc result = searchClass(className);
+        if (result != null) {
+            return result;
+        }
+
+        ClassDoc enclosing = containingClass();
+        while (enclosing != null && enclosing.containingClass() != null) {
+            enclosing = enclosing.containingClass();
+        }
+        if (enclosing == null) {
+            return null;
+        }
+        return ((ClassDocImpl) enclosing).searchClass(className);
+    }
+
+    private ClassDoc searchClass(String className) {
+        TypeElement cls = context.environment.getElementUtils().getTypeElement(className);
+        if (cls != null) {
+            return ClassDocImpl.create(cls, context);
+        }
+
+        for (ClassDoc nested : innerClasses()) {
+            if (nested.name().equals(className) || nested.name().endsWith("." + className)) {
+                return nested;
+            } else {
+                ClassDoc inNested = ((ClassDocImpl) nested).searchClass(className);
+                if (inNested != null) {
+                    return inNested;
+                }
+            }
+        }
+
+        ClassDoc inPackage = containingPackage().findClass(className);
+        if (inPackage != null) {
+            return inPackage;
+        }
+
+        //
+
+        return null;
+    }
+
+    @Override
+    @Unused
+    public ClassDoc[] importedClasses() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused
+    public PackageDoc[] importedPackages() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public String typeName() {
+        return name();
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String qualifiedTypeName() {
+        return qualifiedName();
+    }
+
+    private String simpleTypeName;
+
+    @Override
+    @Used(implemented = true)
+    public String simpleTypeName() {
+        if (simpleTypeName == null) {
+            simpleTypeName = typeElement.getSimpleName().toString();
+        }
+        return simpleTypeName;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String dimension() {
+        return "";
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isPrimitive() {
+        return false;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc asClassDoc() {
+        return this;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ParameterizedType asParameterizedType() {
+        return null;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public TypeVariable asTypeVariable() {
+        return null;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public WildcardType asWildcardType() {
+        return null;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public AnnotatedType asAnnotatedType() {
+        return null;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public AnnotationTypeDoc asAnnotationTypeDoc() {
+        return null;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public Type getElementType() {
+        return null;
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/ConstructorDocImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ConstructorDocImpl.java
new file mode 100644
index 0000000..324cb98
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ConstructorDocImpl.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.ConstructorDoc;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+
+class ConstructorDocImpl extends ExecutableMemberDocImpl implements ConstructorDoc {
+
+    protected ConstructorDocImpl(ExecutableElement e, Context context) {
+        super(e, context);
+    }
+
+    static ConstructorDocImpl create(ExecutableElement e, Context context) {
+        return context.caches.constructors.computeIfAbsent(e,
+                el -> new ConstructorDocImpl(el, context));
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public boolean isConstructor() {
+        return true;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String name() {
+        return executableElement.getEnclosingElement().getSimpleName().toString();
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String qualifiedName() {
+        var enclosingClass = executableElement.getEnclosingElement();
+        return switch (enclosingClass.getKind()) {
+            case CLASS, INTERFACE, ANNOTATION_TYPE, ENUM ->
+                    ((TypeElement) enclosingClass).getQualifiedName().toString();
+            default -> throw new UnsupportedOperationException("Expected CLASS, INTERFACE, "
+                    + "ANNOTATION_TYPE or ENUM, but got " + enclosingClass.getKind());
+        };
+    }
+
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/Context.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/Context.java
new file mode 100644
index 0000000..cfa3bb8
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/Context.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.sun.javadoc.Doc;
+import com.sun.source.doctree.DocTree;
+import com.sun.source.doctree.ParamTree;
+import com.sun.source.doctree.SeeTree;
+import com.sun.source.doctree.SerialFieldTree;
+import com.sun.source.doctree.ThrowsTree;
+import java.util.HashMap;
+import java.util.Map;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.WildcardType;
+import javax.lang.model.util.SimpleElementVisitor14;
+import jdk.javadoc.doclet.DocletEnvironment;
+
+/**
+ * Holds temporary objects required to construct {@link RootDocImpl} from a {@link
+ * jdk.javadoc.doclet.DocletEnvironment}.
+ */
+class Context {
+
+    public final DocletEnvironment environment;
+    public final Caches caches = new Caches();
+    public final DocletElementUtils docletElementUtils;
+
+    public Doc obtain(Element element) {
+        return OBTAIN_VISITOR.visit(element, this);
+    }
+
+    public static class Caches {
+
+        public final Map<TypeElement, ClassDocImpl> classes = new HashMap<>();
+        public final Map<TypeElement, AnnotationTypeDocImpl> annotations = new HashMap<>();
+        public final Map<PackageElement, PackageDocImpl> packages = new HashMap<>();
+        public final Map<ExecutableElement, AnnotationMethodDocImpl> annotationMethods =
+                new HashMap<>();
+        public final Map<AnnotationValue, AnnotationValueImpl> annotationValues = new HashMap<>();
+        public final Map<ExecutableElement, ConstructorDocImpl> constructors = new HashMap<>();
+        public final Map<ExecutableElement, MethodDocImpl> methods = new HashMap<>();
+        public final Map<VariableElement, FieldDocImpl> fields = new HashMap<>();
+        public final Map<VariableElement, ParameterImpl> parameters = new HashMap<>();
+
+        public final Tags tags = new Tags();
+        public final Types types = new Types();
+
+        public static class Tags {
+
+            public final Map<Element, Map<DocTree, TagImpl>> generic = new HashMap<>();
+            public final Map<Element, Map<SeeTree, SeeTagImpl>> see = new HashMap<>();
+            public final Map<Element, Map<SerialFieldTree, SerialFieldTagImpl>> serialField =
+                    new HashMap<>();
+            public final Map<Element, Map<ParamTree, ParamTagImpl>> param = new HashMap<>();
+            public final Map<Element, Map<ThrowsTree, ThrowsTagImpl>> throwz = new HashMap<>();
+        }
+
+        public static class Types {
+
+            public final Map<TypeMirror, TypeImpl> common = new HashMap<>();
+            public final Map<DeclaredType, AnnotatedTypeImpl> annotated = new HashMap<DeclaredType, AnnotatedTypeImpl>();
+            public final Map<WildcardType, WildcardTypeImpl> wildcard = new HashMap<>();
+            public final Map<DeclaredType, ParameterizedTypeImpl> parameterized = new HashMap<>();
+            public final Map<TypeVariable, TypeVariableImpl> typevar = new HashMap<>();
+            public final Map<ArrayType, ArrayTypeImpl> array = new HashMap<>();
+        }
+    }
+
+    public Context(DocletEnvironment environment) {
+        this.environment = environment;
+        this.docletElementUtils = new DocletElementUtils(environment);
+    }
+
+    private static final SimpleElementVisitor14<Doc, Context> OBTAIN_VISITOR =
+            new SimpleElementVisitor14<>() {
+
+                @Override
+                public Doc visitPackage(PackageElement e, Context context) {
+                    return PackageDocImpl.create(e, context);
+                }
+
+                @Override
+                public Doc visitType(TypeElement e, Context context) {
+                    return switch (e.getKind()) {
+                        case CLASS, ENUM, INTERFACE -> ClassDocImpl.create(e, context);
+                        case ANNOTATION_TYPE -> AnnotationTypeDocImpl.create(e, context);
+                        case RECORD -> throw new UnsupportedOperationException(
+                                "Records not yet supported");
+                        default -> throw new IllegalArgumentException(
+                                "Expected ANNOTATION_TYPE, CLASS, "
+                                        + "ENUM, INTERFACE, or RECORD; but got " + e.getKind());
+                    };
+                }
+            };
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/DocErrorReporterImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/DocErrorReporterImpl.java
new file mode 100644
index 0000000..6687365
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/DocErrorReporterImpl.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.sun.javadoc.DocErrorReporter;
+import com.sun.javadoc.SourcePosition;
+
+class DocErrorReporterImpl implements DocErrorReporter {
+
+    /**
+     * Print error message and increment error count.
+     *
+     * @param msg message to print
+     */
+    @Override
+    @Unused
+    public void printError(String msg) {
+        throw new UnsupportedOperationException("not yet implemented");
+        // TODO(nikitai): implement this printError(...).
+    }
+
+    /**
+     * Print an error message and increment error count.
+     *
+     * @param pos the position item where the error occurs
+     * @param msg message to print
+     * @since 1.4
+     */
+    @Override
+    @Unused
+    public void printError(SourcePosition pos, String msg) {
+        throw new UnsupportedOperationException("not yet implemented");
+        // TODO(nikitai): implement this printError(...).
+    }
+
+    /**
+     * Print warning message and increment warning count.
+     *
+     * @param msg message to print
+     */
+    @Override
+    @Unused
+    public void printWarning(String msg) {
+        throw new UnsupportedOperationException("not yet implemented");
+        // TODO(nikitai): implement this printWarning(...).
+    }
+
+    /**
+     * Print warning message and increment warning count.
+     *
+     * @param pos the position item where the warning occurs
+     * @param msg message to print
+     * @since 1.4
+     */
+    @Override
+    @Unused
+    public void printWarning(SourcePosition pos, String msg) {
+        throw new UnsupportedOperationException("not yet implemented");
+        // TODO(nikitai): implement this printWarning(...).
+    }
+
+    /**
+     * Print a message.
+     *
+     * @param msg message to print
+     */
+    @Override
+    @Unused
+    public void printNotice(String msg) {
+        throw new UnsupportedOperationException("not yet implemented");
+        // TODO(nikitai): implement this printNotice(...).
+    }
+
+    /**
+     * Print a message.
+     *
+     * @param pos the position item where the message occurs
+     * @param msg message to print
+     * @since 1.4
+     */
+    @Override
+    @Unused
+    public void printNotice(SourcePosition pos, String msg) {
+        throw new UnsupportedOperationException("not yet implemented");
+        // TODO(nikitai): implement this printNotice(...).
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/DocImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/DocImpl.java
new file mode 100644
index 0000000..0ad7c6f
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/DocImpl.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.Doc;
+import com.sun.javadoc.SeeTag;
+import com.sun.javadoc.SourcePosition;
+import com.sun.javadoc.Tag;
+import com.sun.source.doctree.DocCommentTree;
+import com.sun.source.doctree.DocTree;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.lang.model.element.Element;
+
+abstract class DocImpl<T extends Element> implements Doc, Comparable<Object> {
+
+    protected final T element;
+    protected final Context context;
+
+    protected DocImpl(T e, Context context) {
+        this.element = e;
+        this.context = context;
+    }
+
+    private String commentText;
+
+    @Override
+    @Unused(implemented = true)
+    public String commentText() {
+        if (commentText == null) {
+            var dt = context.environment.getDocTrees().getDocCommentTree(element);
+            commentText = dt.getFullBody().stream()
+                    .map(DocTree::toString)
+                    .collect(Collectors.joining())
+                    .trim();
+        }
+        return commentText;
+    }
+
+    private Tag[] tags;
+
+    @Override
+    @Unused(implemented = true)
+    public Tag[] tags() {
+        if (tags == null) {
+            DocCommentTree tree = context.environment.getDocTrees().getDocCommentTree(element);
+            List<? extends DocTree> blockTags = tree.getBlockTags();
+
+            tags = blockTags
+                    .stream()
+                    .map(docTree -> TagImpl.create(docTree, element, context))
+                    .toArray(Tag[]::new);
+        }
+        return tags;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public Tag[] tags(String kind) {
+        return Arrays.stream(tags())
+                .filter(t -> t.kind().equals(kind))
+                .toArray(Tag[]::new);
+    }
+
+    private SeeTag[] seeTags;
+
+    @Override
+    @Unused(implemented = true)
+    public SeeTag[] seeTags() {
+        if (seeTags == null) {
+            seeTags = Arrays.stream(tags())
+                    .filter(t -> t instanceof SeeTagImpl)
+                    .toArray(SeeTag[]::new);
+        }
+        return seeTags;
+    }
+
+    private Tag[] inlineTags;
+
+    @Override
+    @Used(implemented = true)
+    public Tag[] inlineTags() {
+        if (inlineTags == null) {
+            var dt = context.environment.getDocTrees().getDocCommentTree(element);
+            if (dt == null) {
+                inlineTags = new Tag[0];
+            } else {
+                List<DocTree> tags = new ArrayList<>(dt.getFullBody());
+                inlineTags = tags.stream()
+                        .map(tag -> TagImpl.create(tag, element, context))
+                        .toArray(Tag[]::new);
+            }
+        }
+        return inlineTags;
+    }
+
+    private Tag[] firstSentenceTags;
+
+    @Override
+    @Unused(implemented = true)
+    public Tag[] firstSentenceTags() {
+        if (firstSentenceTags == null) {
+            var dt = context.environment.getDocTrees().getDocCommentTree(element);
+            firstSentenceTags = dt.getFirstSentence().stream()
+                    .map(tag -> TagImpl.create(tag, element, context))
+                    .toArray(Tag[]::new);
+        }
+        return firstSentenceTags;
+    }
+
+    private String getRawCommentText;
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implNote this implementation prettifies javadoc a bit; previous implementation returned
+     * javadoc as-is without any modifications.
+     *
+     */
+    @Override
+    @Used(implemented = true)
+    public String getRawCommentText() {
+        if (getRawCommentText == null) {
+            var dt = context.environment.getDocTrees().getDocCommentTree(element);
+            if (dt == null) {
+                getRawCommentText = "";
+            } else {
+                //TODO: this implementation is slightly different, consider reimplementing.
+                getRawCommentText = dt.toString();
+            }
+        }
+        return getRawCommentText;
+    }
+
+    @Override
+    @Unused
+    public void setRawCommentText(String rawDocumentation) {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String toString() {
+        return qualifiedName();
+    }
+
+    @Override
+    public abstract String name();
+
+    public abstract String qualifiedName();
+
+    @Override
+    public int compareTo(Object obj) {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public boolean isField() {
+        return false;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public boolean isEnumConstant() {
+        return false;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public boolean isConstructor() {
+        return false;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public boolean isMethod() {
+        return false;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isAnnotationTypeElement() {
+        return false;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isInterface() {
+        return false;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isException() {
+        return false;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isError() {
+        return false;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isEnum() {
+        return false;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public boolean isAnnotationType() {
+        return false;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isOrdinaryClass() {
+        return false;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public boolean isClass() {
+        return false;
+    }
+
+    @Override
+    public abstract boolean isIncluded();
+
+    @Override
+    @Used(implemented = true)
+    public SourcePosition position() {
+        return SourcePositionImpl.STUB;
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/DocletElementUtils.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/DocletElementUtils.java
new file mode 100644
index 0000000..927c572
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/DocletElementUtils.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import jdk.javadoc.doclet.DocletEnvironment;
+
+class DocletElementUtils {
+
+    private final DocletEnvironment env;
+    private final Types typeUtils;
+    private final Elements elementUtils;
+
+    private final TypeMirror exceptionType;
+    private final TypeMirror errorType;
+    private final TypeMirror throwableType;
+
+    private DocletElementUtils() {
+        throw new UnsupportedOperationException("Hide default constructor.");
+    }
+
+    public DocletElementUtils(DocletEnvironment e) {
+        this.env = e;
+        this.typeUtils = e.getTypeUtils();
+        this.elementUtils = e.getElementUtils();
+
+        this.exceptionType = getTypeByName("java.lang.Exception");
+        this.errorType = getTypeByName("java.lang.Error");
+        this.throwableType = getTypeByName("java.lang.Throwable");
+    }
+
+    public boolean isException(Element e) {
+        if (!isClass(e)) {
+            return false;
+        }
+        return typeUtils.isSubtype(e.asType(), exceptionType);
+    }
+
+    public boolean isError(Element e) {
+        if (!isClass(e)) {
+            return false;
+        }
+        return typeUtils.isSubtype(e.asType(), errorType);
+    }
+
+    public boolean isThrowable(Element e) {
+        if (!isClass(e)) {
+            return false;
+        }
+        return typeUtils.isSubtype(e.asType(), throwableType);
+    }
+
+    public boolean isAnnotation(Element e) {
+        return e.getKind() == ElementKind.ANNOTATION_TYPE;
+    }
+
+    public boolean isEnum(Element e) {
+        return e.getKind() == ElementKind.ENUM;
+    }
+
+    public boolean isInterface(Element e) {
+        return e.getKind() == ElementKind.INTERFACE;
+    }
+
+    public boolean isClass(Element e) {
+        return e.getKind() == ElementKind.CLASS;
+    }
+
+    public boolean isPackage(Element e) {
+        return e.getKind() == ElementKind.PACKAGE;
+    }
+
+    private final HashMap<String, TypeMirror> typeMirrorsCache = new HashMap<>();
+
+    public TypeMirror getTypeByName(String name) {
+        TypeMirror mirror = typeMirrorsCache.get(name);
+        if (mirror != null) {
+            return mirror;
+        }
+        TypeElement e = elementUtils.getTypeElement(name);
+        if (e == null || (mirror = e.asType()) == null) {
+            return null;
+        }
+        typeMirrorsCache.put(name, mirror);
+        return mirror;
+    }
+
+    /**
+     * Return the class name without package qualifier but with enclosing class qualifier, e.g. for
+     * {@code java.lang.String} return {@code String} (public class); and for {@code
+     * java.util.Map.Entry} return {@code Map.Entry} (nested class).
+     *
+     * @param e class
+     * @return class name without package qualifier but with enclosing class qualifier
+     */
+    public String getClassNameUntilNotNested(TypeElement e) {
+        Deque<String> acc = new ArrayDeque<>();
+        var it = new EnclosingUntilNotNestedIterator(e, this);
+        it.forEachRemaining(nestedElement -> acc.addFirst(nestedElement.getSimpleName().toString()));
+        return String.join(".", acc);
+    }
+
+    public TypeElement getEnclosingTypeElement(Element e) {
+        if (isPackage(e)) {
+            return null;
+
+        }
+        Element encl = e.getEnclosingElement();
+        if (isPackage(encl)) {
+            return null;
+        }
+        while (!(isClass(encl) || isEnum(encl) || isInterface(encl) || isAnnotation(encl))) {
+            encl = encl.getEnclosingElement();
+            if (encl == null) {
+                return null;
+            }
+        }
+        return (TypeElement) encl;
+    }
+
+    /**
+     * Iterates over the immediately lexically enclosing elements for a nested type up until type
+     * is no longer nested.
+     */
+    private static class EnclosingUntilNotNestedIterator implements Iterator<TypeElement> {
+
+        private TypeElement current;
+        private final DocletElementUtils utils;
+
+        public EnclosingUntilNotNestedIterator(TypeElement typeElement, DocletElementUtils utils) {
+            this.current = typeElement;
+            this.utils = utils;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return (current != null);
+        }
+
+        @Override
+        public TypeElement next() {
+            if (!hasNext()) {
+                throw new NoSuchElementException();
+            }
+            TypeElement ret = current;
+            current = utils.getEnclosingTypeElement(current);
+            return ret;
+        }
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/ErrorTypeImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ErrorTypeImpl.java
new file mode 100644
index 0000000..e7faa7f
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ErrorTypeImpl.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.AnnotationDesc;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.ProgramElementDoc;
+import com.sun.javadoc.Type;
+import com.sun.javadoc.TypeVariable;
+import java.util.Objects;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+
+class ErrorTypeImpl extends ClassDocImpl {
+
+    private final javax.lang.model.type.ErrorType errorType;
+
+    protected ErrorTypeImpl(TypeElement el, javax.lang.model.type.ErrorType errorType,
+            Context context) {
+        super(el, context);
+        this.errorType = errorType;
+    }
+
+    static ErrorTypeImpl create(javax.lang.model.type.ErrorType errorType,
+            Context context) {
+        var typeEl = (TypeElement) errorType.asElement();
+        var typeImpl = context.caches.classes.computeIfAbsent(typeEl,
+                el -> new ErrorTypeImpl(el, errorType, context));
+
+        // On rare occasions it can happen that the errorType had already been cached as a
+        // ClassDocImpl instead of ErrorTypeImpl. In that case recreate the ErrorTypeImpl and store
+        // it in the cache.
+        if (!(typeImpl instanceof ErrorTypeImpl)) {
+            typeImpl = new ErrorTypeImpl(typeEl, errorType, context);
+            context.caches.classes.put(typeEl, typeImpl);
+        }
+
+        return (ErrorTypeImpl)typeImpl;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isIncluded() {
+        return false;
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/ExecutableMemberDocImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ExecutableMemberDocImpl.java
new file mode 100644
index 0000000..650856f
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ExecutableMemberDocImpl.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.ExecutableMemberDoc;
+import com.sun.javadoc.ParamTag;
+import com.sun.javadoc.Parameter;
+import com.sun.javadoc.SourcePosition;
+import com.sun.javadoc.ThrowsTag;
+import com.sun.javadoc.Type;
+import com.sun.javadoc.TypeVariable;
+import java.lang.reflect.Modifier;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements.Origin;
+
+abstract class ExecutableMemberDocImpl extends MemberDocImpl<ExecutableElement> implements
+        ExecutableMemberDoc {
+
+    protected final ExecutableElement executableElement;
+
+    // Cached fields
+    private ClassDoc[] thrownExceptions;
+    private Parameter[] parameters;
+    private String signature;
+    private String flatSignature;
+    private TypeVariable[] typeParameters;
+
+    protected ExecutableMemberDocImpl(ExecutableElement e, Context context) {
+        super(e, context);
+        this.executableElement = e;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isNative() {
+        return (reflectModifiers & Modifier.NATIVE) != 0;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isSynchronized() {
+        return (reflectModifiers & Modifier.SYNCHRONIZED) != 0;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isVarArgs() {
+        return executableElement.isVarArgs();
+    }
+
+    @Used(implemented = true)
+    public boolean isSynthetic() {
+        return context.environment.getElementUtils()
+                .getOrigin(executableElement) == Origin.SYNTHETIC;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isIncluded() {
+        return context.environment.isIncluded(executableElement);
+    }
+
+    @Override
+    @Unused
+    public ThrowsTag[] throwsTags() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused
+    public ParamTag[] paramTags() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused
+    public ParamTag[] typeParamTags() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc[] thrownExceptions() {
+        if (thrownExceptions == null) {
+            thrownExceptions = executableElement.getThrownTypes()
+                    .stream()
+                    .map(typeMirror -> TypeImpl.create(typeMirror, context).asClassDoc())
+                    .filter(Objects::nonNull)
+                    .toArray(ClassDoc[]::new);
+        }
+        return thrownExceptions;
+    }
+
+    @Override
+    @Unused
+    public Type[] thrownExceptionTypes() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Used(implemented = true)
+    public Parameter[] parameters() {
+        if (parameters == null) {
+            parameters = executableElement.getParameters()
+                    .stream()
+                    .map(variableElement -> ParameterImpl.create(variableElement, context))
+                    .toArray(ParameterImpl[]::new);
+        }
+        return parameters;
+    }
+
+    @Override
+    @Unused
+    public Type receiverType() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Used(implemented = true)
+    public TypeVariable[] typeParameters() {
+        if (typeParameters == null) {
+            typeParameters = executableElement.getTypeParameters()
+                    .stream()
+                    .map(tpe -> TypeVariableImpl.create(tpe.asType(), context))
+                    .toArray(TypeVariable[]::new);
+        }
+        return typeParameters;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String signature() {
+        if (signature == null) {
+             String params = executableElement.getParameters()
+                     .stream()
+                     .map(param -> param.asType().toString())
+                     .collect(Collectors.joining(", "));
+            signature = "(" + params + ")";
+        }
+        return signature;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String flatSignature() {
+        if (flatSignature == null) {
+            String params = executableElement.getParameters()
+                    .stream()
+                    .map(param -> {
+                        TypeMirror mirror = param.asType();
+                        Type t = TypeImpl.create(mirror, context);
+                        return t.simpleTypeName();
+                    })
+                    .collect(Collectors.joining(", "));
+            flatSignature = "(" + params + ")";
+        }
+        return flatSignature;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public SourcePosition position() {
+        return SourcePositionImpl.STUB;
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/FieldDocImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/FieldDocImpl.java
new file mode 100644
index 0000000..3f61a61
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/FieldDocImpl.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.FieldDoc;
+import com.sun.javadoc.SerialFieldTag;
+import com.sun.javadoc.Type;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.util.Elements.Origin;
+
+class FieldDocImpl extends MemberDocImpl<VariableElement> implements FieldDoc {
+
+    protected final VariableElement variableElement;
+
+    protected FieldDocImpl(VariableElement e, Context context) {
+        super(e, context);
+        variableElement = e;
+    }
+
+    static FieldDocImpl create(VariableElement e, Context context) {
+        return context.caches.fields.computeIfAbsent(e, el -> new FieldDocImpl(el, context));
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isSynthetic() {
+        return context.environment.getElementUtils().getOrigin(variableElement) == Origin.SYNTHETIC;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String name() {
+        return variableElement.getSimpleName().toString();
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String qualifiedName() {
+        var enclosingClass = variableElement.getEnclosingElement();
+        return switch (enclosingClass.getKind()) {
+            case CLASS, INTERFACE, ANNOTATION_TYPE, ENUM ->
+                    ((TypeElement) enclosingClass).getQualifiedName().toString() + "."
+                            + variableElement.getSimpleName();
+            default -> throw new UnsupportedOperationException("Expected CLASS, INTERFACE, "
+                    + "ANNOTATION_TYPE or ENUM, but got " + enclosingClass.getKind());
+        };
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isIncluded() {
+        return context.environment.isIncluded(variableElement);
+    }
+
+    @Override
+    @Used(implemented = true)
+    public Type type() {
+        return TypeImpl.create(variableElement.asType(), context);
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isTransient() {
+        return java.lang.reflect.Modifier.isTransient(reflectModifiers);
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isVolatile() {
+        return java.lang.reflect.Modifier.isVolatile(reflectModifiers);
+    }
+
+    @Override
+    @Unused
+    public SerialFieldTag[] serialFieldTags() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Used(implemented = true)
+    public Object constantValue() {
+        var cv = variableElement.getConstantValue();
+        if (cv == null) {
+            return null;
+        }
+        // cv is either a primitive type or a String
+        if (cv instanceof String) {
+            return cv;
+        } else if (cv instanceof Boolean b) {
+            return b;
+        } else if (cv instanceof Byte b) {
+            return (int) b;
+        } else if (cv instanceof Character c) {
+            return (int) c;
+        } else if (cv instanceof Double d) {
+            return d;
+        } else if (cv instanceof Float f) {
+            return f;
+        } else if (cv instanceof Integer i) {
+            return i;
+        } else if (cv instanceof Long l) {
+            return l;
+        } else if (cv instanceof Short s) {
+            return (int) s;
+        } else {
+            throw new IllegalArgumentException("Unexpected constant value of type " + cv.getClass()
+                    + " when expected java.lang.String or primitive type");
+        }
+    }
+
+    @Override
+    @Unused
+    public String constantValueExpression() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/MemberDocImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/MemberDocImpl.java
new file mode 100644
index 0000000..670c649
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/MemberDocImpl.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.sun.javadoc.MemberDoc;
+import javax.lang.model.element.Element;
+
+abstract class MemberDocImpl<T extends Element> extends ProgramElementDocImpl<T> implements
+        MemberDoc {
+
+    protected MemberDocImpl(T e, Context context) {
+        super(e, context);
+    }
+
+    @Override
+    public abstract boolean isSynthetic();
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/MethodDocImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/MethodDocImpl.java
new file mode 100644
index 0000000..20ae382
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/MethodDocImpl.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.MethodDoc;
+import com.sun.javadoc.Type;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+class MethodDocImpl extends ExecutableMemberDocImpl implements MethodDoc {
+
+    protected MethodDocImpl(ExecutableElement e, Context context) {
+        super(e, context);
+    }
+
+    static MethodDocImpl create(ExecutableElement e, Context context) {
+        return context.caches.methods.computeIfAbsent(e,
+                el -> new MethodDocImpl(el, context));
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String name() {
+        return executableElement.getSimpleName().toString();
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String qualifiedName() {
+        var enclosingClass = executableElement.getEnclosingElement();
+        return switch (enclosingClass.getKind()) {
+            case CLASS, INTERFACE, ANNOTATION_TYPE, ENUM, RECORD -> {
+                var enclosingClassName =
+                        ((TypeElement) enclosingClass).getQualifiedName().toString();
+                yield enclosingClassName + "." + name();
+            }
+            default -> throw new UnsupportedOperationException("Expected CLASS, INTERFACE, "
+                    + "ANNOTATION_TYPE, ENUM, or RECORD, but got " + enclosingClass.getKind());
+        };
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public boolean isMethod() {
+        return true;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isAbstract() {
+        return java.lang.reflect.Modifier.isAbstract(reflectModifiers);
+    }
+
+    private Boolean isDefault;
+
+    @Override
+    @Used(implemented = true)
+    public boolean isDefault() {
+        if (isDefault == null) {
+            isDefault = executableElement.getModifiers()
+                    .stream()
+                    .anyMatch(m -> m == Modifier.DEFAULT);
+        }
+        return isDefault;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public Type returnType() {
+        return TypeImpl.create(executableElement.getReturnType(), context);
+    }
+
+    @Override
+    @Unused
+    public ClassDoc overriddenClass() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused
+    public Type overriddenType() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Used(implemented = true)
+    public MethodDoc overriddenMethod() {
+        if (isStatic()) {
+            return null;
+        }
+
+        var enclosingElement = executableElement.getEnclosingElement();
+
+        final Types typeUtils = context.environment.getTypeUtils();
+        final Elements elemUtils = context.environment.getElementUtils();
+
+        return switch (enclosingElement.getKind()) {
+            case CLASS, INTERFACE, ANNOTATION_TYPE, ENUM, RECORD -> {
+                var owningClass = ((TypeElement) enclosingElement);
+                for (TypeMirror superclass = owningClass.getSuperclass();
+                        superclass.getKind() != TypeKind.NONE;
+                        superclass = ((TypeElement) typeUtils.asElement(superclass)).getSuperclass()
+                ) {
+                    TypeElement superclassElem =
+                            (TypeElement) typeUtils.asElement(superclass);
+                    var overriden = ElementFilter.methodsIn(superclassElem.getEnclosedElements())
+                            .stream()
+                            .filter(exe -> elemUtils.overrides(executableElement, exe, owningClass))
+                            .findFirst();
+                    if (overriden.isPresent()) {
+                        yield MethodDocImpl.create(overriden.get(), context);
+                    }
+                }
+                yield null;
+            }
+            default -> throw new UnsupportedOperationException("Expected CLASS, INTERFACE, "
+                    + "ANNOTATION_TYPE or ENUM, but got " + enclosingElement.getKind());
+        };
+    }
+
+    @Override
+    @Unused
+    public boolean overrides(MethodDoc meth) {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/PackageDocImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/PackageDocImpl.java
new file mode 100644
index 0000000..2c60994
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/PackageDocImpl.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.AnnotationDesc;
+import com.sun.javadoc.AnnotationTypeDoc;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.PackageDoc;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+
+class PackageDocImpl extends DocImpl<PackageElement> implements PackageDoc {
+
+    private final PackageElement packageElement;
+
+
+    private String qualifiedName;
+    private ClassDoc[] allClasses;
+    private ClassDoc[] allClassesFiltered;
+    private ClassDoc[] ordinaryClasses;
+    private ClassDoc[] exceptions;
+    private ClassDoc[] errors;
+    private ClassDoc[] enums;
+    private ClassDoc[] interfaces;
+    private AnnotationTypeDoc[] annotationTypes;
+
+    protected PackageDocImpl(PackageElement e, Context context) {
+        super(e, context);
+        this.packageElement = e;
+    }
+
+    static PackageDocImpl create(PackageElement e, Context context) {
+        var ret = context.caches.packages.computeIfAbsent(e, el -> new PackageDocImpl(el, context));
+        return ret;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc[] allClasses(boolean filter) {
+        if (!filter && allClasses != null) {
+            return allClasses;
+        }
+        if (filter && allClassesFiltered != null) {
+            return allClassesFiltered;
+        }
+
+        List<ClassDocImpl> classes =
+                filterEnclosedElements(e -> e.getKind() == ElementKind.CLASS ||
+                        e.getKind() == ElementKind.INTERFACE ||
+                        e.getKind() == ElementKind.ENUM ||
+                        e.getKind() == ElementKind.ANNOTATION_TYPE)
+                .filter(e -> !filter || context.environment.isSelected(e))
+                .map(e -> {
+                    if (e.getKind() == ElementKind.ANNOTATION_TYPE) {
+                        return AnnotationTypeDocImpl.create((TypeElement) e, context);
+                    }
+                    return ClassDocImpl.create((TypeElement) e, context);
+                })
+                .toList();
+
+        if (filter) {
+            return allClassesFiltered = classes.toArray(ClassDoc[]::new);
+        } else {
+            return allClasses = classes.toArray(ClassDoc[]::new);
+        }
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc[] allClasses() {
+        return allClasses(true);
+    }
+
+    private Stream<Element> filterEnclosedElements(Predicate<Element> predicate) {
+        EnclosedElementsIterator it = new EnclosedElementsIterator(packageElement);
+        return StreamSupport
+                .stream(Spliterators.spliteratorUnknownSize(it, Spliterator.ORDERED), false)
+                .filter(context.environment::isIncluded)
+                .filter(predicate);
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc[] ordinaryClasses() {
+        if (ordinaryClasses == null) {
+            ordinaryClasses = filterEnclosedElements(e -> e.getKind() == ElementKind.CLASS)
+                    .map(e -> ClassDocImpl.create((TypeElement) e, context))
+                    .filter(cls -> !cls.isError() && !cls.isException())
+                    .toArray(ClassDocImpl[]::new);
+        }
+        return ordinaryClasses;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc[] exceptions() {
+        if (exceptions == null) {
+            exceptions = filterEnclosedElements(e -> e.getKind() == ElementKind.CLASS)
+                    .map(element -> ClassDocImpl.create((TypeElement) element, context))
+                    .filter(ClassDocImpl::isException)
+                    .toArray(ClassDocImpl[]::new);
+        }
+        return exceptions;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc[] errors() {
+        if (errors == null) {
+            errors = filterEnclosedElements(e -> e.getKind() == ElementKind.CLASS)
+                    .map(element -> ClassDocImpl.create((TypeElement) element, context))
+                    .filter(ClassDocImpl::isError)
+                    .toArray(ClassDocImpl[]::new);
+        }
+        return errors;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc[] enums() {
+        if (enums == null) {
+            enums = filterEnclosedElements(e -> e.getKind() == ElementKind.ENUM)
+                    .map(element -> ClassDocImpl.create((TypeElement) element, context))
+                    .toArray(ClassDocImpl[]::new);
+        }
+        return enums;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc[] interfaces() {
+        if (interfaces == null) {
+            interfaces = filterEnclosedElements(e -> e.getKind() == ElementKind.INTERFACE)
+                    .map(element -> ClassDocImpl.create((TypeElement) element, context))
+                    .toArray(ClassDocImpl[]::new);
+        }
+        return interfaces;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public AnnotationTypeDoc[] annotationTypes() {
+        if (annotationTypes == null) {
+            annotationTypes = filterEnclosedElements(
+                    e -> e.getKind() == ElementKind.ANNOTATION_TYPE)
+                    .map(element -> AnnotationTypeDocImpl.create((TypeElement) element, context))
+                    .toArray(AnnotationTypeDocImpl[]::new);
+        }
+        return annotationTypes;
+    }
+
+    @Override
+    @Unused
+    public AnnotationDesc[] annotations() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc findClass(String className) {
+        for (ClassDoc c : allClasses()) {
+            if (c.name().equals(className)) {
+                return c;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isIncluded() {
+        return context.environment.isIncluded(packageElement);
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String name() {
+        return qualifiedName();
+    }
+
+    @Override
+    public String qualifiedName() {
+        if (qualifiedName == null) {
+            qualifiedName = packageElement.getQualifiedName().toString();
+        }
+        return qualifiedName;
+    }
+
+    private static final class EnclosedElementsIterator implements Iterator<Element> {
+
+        private final Deque<Element> queue;
+
+        public EnclosedElementsIterator(Element element) {
+            this.queue = new ArrayDeque<>(element.getEnclosedElements());
+        }
+
+        @Override
+        public boolean hasNext() {
+            return !queue.isEmpty();
+        }
+
+        @Override
+        public Element next() {
+            Element current = queue.pop();
+            if (!current.getEnclosedElements().isEmpty()) {
+                queue.addAll(current.getEnclosedElements());
+            }
+            return current;
+        }
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/ParamTagImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ParamTagImpl.java
new file mode 100644
index 0000000..e329cc1
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ParamTagImpl.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.ParamTag;
+import com.sun.source.doctree.ParamTree;
+import java.util.HashMap;
+import java.util.stream.Collectors;
+import javax.lang.model.element.Element;
+
+class ParamTagImpl extends TagImpl implements ParamTag {
+
+    private final ParamTree paramTree;
+
+    protected ParamTagImpl(ParamTree paramTree, Element owner, Context context) {
+        super(paramTree, owner, context);
+        this.paramTree = paramTree;
+    }
+
+    static ParamTagImpl create(ParamTree paramTree, Element owner, Context context) {
+        var tagsOfElement = context.caches.tags.param.computeIfAbsent(owner,
+                el -> new HashMap<>());
+        return tagsOfElement.computeIfAbsent(paramTree, el -> new ParamTagImpl(el, owner, context));
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String parameterName() {
+        return paramTree.getName().getName().toString();
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String parameterComment() {
+        return paramTree.getDescription()
+                .stream()
+                .map(Object::toString)
+                .collect(Collectors.joining(" "));
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isTypeParameter() {
+        return paramTree.isTypeParameter();
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/ParameterImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ParameterImpl.java
new file mode 100644
index 0000000..4b32607
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ParameterImpl.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.AnnotationDesc;
+import com.sun.javadoc.Parameter;
+import com.sun.javadoc.Type;
+import com.sun.javadoc.TypeVariable;
+import javax.lang.model.element.VariableElement;
+
+class ParameterImpl implements Parameter {
+
+    private final String name;
+    private final Type type;
+    private final AnnotationDescImpl[] annotations;
+
+    public ParameterImpl(VariableElement variableElement, Context context) {
+        this.name = variableElement.getSimpleName().toString();
+        this.type = TypeImpl.create(variableElement.asType(), context);
+        this.annotations = variableElement.getAnnotationMirrors()
+                .stream()
+                .map(am -> new AnnotationDescImpl(am, context))
+                .toArray(AnnotationDescImpl[]::new);
+    }
+
+    static ParameterImpl create(VariableElement ve, Context context) {
+        return context.caches.parameters.computeIfAbsent(ve, el -> new ParameterImpl(el, context));
+    }
+
+    @Override
+    @Used(implemented = true)
+    public Type type() {
+        return type;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String name() {
+        return name;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String typeName() {
+        String result;
+        if (type instanceof ClassDocImpl || type instanceof TypeVariable) {
+            result = type.typeName() + type.dimension();
+        } else {
+            result = type.qualifiedTypeName() + type.dimension();
+        }
+        return result;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public AnnotationDesc[] annotations() {
+        return annotations;
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/ParameterizedTypeImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ParameterizedTypeImpl.java
new file mode 100644
index 0000000..5374947
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ParameterizedTypeImpl.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.ParameterizedType;
+import com.sun.javadoc.Type;
+import java.util.Objects;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+class ParameterizedTypeImpl extends TypeImpl implements ParameterizedType {
+
+    private final DeclaredType declaredType;
+
+    // Cached fields
+    private Type[] typeArguments;
+
+    protected ParameterizedTypeImpl(DeclaredType declaredType, Context context) {
+        super(declaredType, context);
+        this.declaredType = declaredType;
+    }
+
+    static ParameterizedTypeImpl create(DeclaredType declaredType, Context context) {
+        return context.caches.types.parameterized.computeIfAbsent(declaredType,
+                el -> new ParameterizedTypeImpl(el, context));
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ParameterizedType asParameterizedType() {
+        return this;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public Type[] typeArguments() {
+        if (typeArguments == null) {
+            typeArguments = declaredType.getTypeArguments()
+                    .stream()
+                    .map(typeMirror -> TypeImpl.create(typeMirror, context))
+                    .toArray(Type[]::new);
+        }
+        return typeArguments;
+    }
+
+    @Override
+    @Unused
+    public Type superclassType() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused
+    public Type[] interfaceTypes() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused
+    public Type containingType() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    public ClassDoc asClassDoc() {
+        TypeMirror erasure = context.environment.getTypeUtils().erasure(declaredType);
+        Type type = create(erasure, context);
+        Objects.requireNonNull(type);
+        return type.asClassDoc();
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/PrimitiveTypeImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/PrimitiveTypeImpl.java
new file mode 100644
index 0000000..adc6755
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/PrimitiveTypeImpl.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.AnnotatedType;
+import com.sun.javadoc.AnnotationTypeDoc;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.ParameterizedType;
+import com.sun.javadoc.Type;
+import com.sun.javadoc.TypeVariable;
+import com.sun.javadoc.WildcardType;
+
+public enum PrimitiveTypeImpl implements Type {
+
+    BOOLEAN("boolean"),
+    BYTE("byte"),
+    CHAR("char"),
+    DOUBLE("double"),
+    FLOAT("float"),
+    INT("int"),
+    LONG("long"),
+    SHORT("short"),
+    VOID("void"),
+    NULL("null");
+
+    private final String name;
+
+    PrimitiveTypeImpl(String name) {
+        this.name = name;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public String typeName() {
+        return name;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String qualifiedTypeName() {
+        return name;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String simpleTypeName() {
+        return name;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String dimension() {
+        return "";
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isPrimitive() {
+        return true;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc asClassDoc() {
+        return null;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ParameterizedType asParameterizedType() {
+        return null;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public TypeVariable asTypeVariable() {
+        return null;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public WildcardType asWildcardType() {
+        return null;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public AnnotatedType asAnnotatedType() {
+        return null;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public AnnotationTypeDoc asAnnotationTypeDoc() {
+        return null;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public Type getElementType() {
+        return null;
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/ProgramElementDocImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ProgramElementDocImpl.java
new file mode 100644
index 0000000..bf9803d
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ProgramElementDocImpl.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.AnnotationDesc;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.PackageDoc;
+import com.sun.javadoc.ProgramElementDoc;
+import java.util.Set;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+
+abstract class ProgramElementDocImpl<T extends Element> extends DocImpl<T> implements
+        ProgramElementDoc {
+
+    /**
+     * Direct mapping of {@link javax.lang.model.element.Modifier} to {@link
+     * java.lang.reflect.Modifier}.
+     *
+     * @implNote Can be updated by subclasses ({@link ClassDocImpl} and {@link
+     * AnnotationTypeDocImpl} to add {@link java.lang.reflect.Modifier#INTERFACE} modifier.
+     * @see javax.lang.model.element.Modifier
+     * @see java.lang.reflect.Modifier
+     * @see ClassDocImpl
+     * @see AnnotationTypeDocImpl
+     */
+    protected int reflectModifiers;
+
+    protected T element;
+
+    private AnnotationDescImpl[] annotations;
+
+    protected ProgramElementDocImpl(T e, Context context) {
+        super(e, context);
+
+        this.element = e;
+        this.reflectModifiers = elementModifiersToReflectModifiers(e.getModifiers());
+    }
+
+    private int elementModifiersToReflectModifiers(Set<Modifier> modifiers) {
+        int mods = 0;
+        for (Modifier m : modifiers) {
+            switch (m) {
+                case ABSTRACT -> mods |= java.lang.reflect.Modifier.ABSTRACT;
+                case FINAL -> mods |= java.lang.reflect.Modifier.FINAL;
+                case PRIVATE -> mods |= java.lang.reflect.Modifier.PRIVATE;
+                case PROTECTED -> mods |= java.lang.reflect.Modifier.PROTECTED;
+                case PUBLIC -> mods |= java.lang.reflect.Modifier.PUBLIC;
+                case NATIVE -> mods |= java.lang.reflect.Modifier.NATIVE;
+                case STATIC -> mods |= java.lang.reflect.Modifier.STATIC;
+                case STRICTFP -> mods |= java.lang.reflect.Modifier.STRICT;
+                case SYNCHRONIZED -> mods |= java.lang.reflect.Modifier.SYNCHRONIZED;
+                case TRANSIENT -> mods |= java.lang.reflect.Modifier.TRANSIENT;
+                case VOLATILE -> mods |= java.lang.reflect.Modifier.VOLATILE;
+                case DEFAULT, NON_SEALED, SEALED -> {
+                    // Exhaust the remaining element modifiers that are not present in
+                    // java.lang.reflect.Modifier.
+                }
+                default -> throw new UnsupportedOperationException("Unexpected modifier: " + m);
+            }
+        }
+        return mods;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc containingClass() {
+        Element cur = element.getEnclosingElement();
+        while (cur != null && cur.getKind() != ElementKind.ANNOTATION_TYPE
+                && cur.getKind() != ElementKind.CLASS
+                && cur.getKind() != ElementKind.ENUM
+                && cur.getKind() != ElementKind.INTERFACE
+                && cur.getKind() != ElementKind.RECORD) {
+            cur = cur.getEnclosingElement();
+        }
+        if (cur == null) {
+            return null;
+        }
+        return switch (cur.getKind()) {
+            case CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, RECORD -> ClassDocImpl.create((TypeElement) cur,
+                    context);
+            default -> null;
+        };
+    }
+
+    @Override
+    @Used(implemented = true)
+    public PackageDoc containingPackage() {
+        Element cur = element.getEnclosingElement();
+        while (cur.getKind() != ElementKind.PACKAGE) {
+            cur = cur.getEnclosingElement();
+        }
+        return PackageDocImpl.create((PackageElement) cur, context);
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public int modifierSpecifier() {
+        return reflectModifiers;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public String modifiers() {
+        return java.lang.reflect.Modifier.toString(reflectModifiers);
+    }
+
+    @Override
+    @Used(implemented = true)
+    public AnnotationDesc[] annotations() {
+        if (annotations == null) {
+            annotations = element.getAnnotationMirrors()
+                    .stream()
+                    // b/270334687: Filter out elements that are not ANNOTATION_TYPE
+                    .filter(am -> ((TypeElement) am.getAnnotationType().asElement()).getKind() == ElementKind.ANNOTATION_TYPE)
+                    .map(am -> new AnnotationDescImpl(am, context))
+                    .toArray(AnnotationDescImpl[]::new);
+        }
+        return annotations;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isPublic() {
+        return java.lang.reflect.Modifier.isPublic(reflectModifiers);
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isProtected() {
+        return java.lang.reflect.Modifier.isProtected(reflectModifiers);
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isPrivate() {
+        return java.lang.reflect.Modifier.isPrivate(reflectModifiers);
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isPackagePrivate() {
+        return !(isPublic() || isPrivate() || isProtected());
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isStatic() {
+        return java.lang.reflect.Modifier.isStatic(reflectModifiers);
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isFinal() {
+        return java.lang.reflect.Modifier.isFinal(reflectModifiers);
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/RootDocImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/RootDocImpl.java
new file mode 100644
index 0000000..d6e412e
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/RootDocImpl.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.PackageDoc;
+import com.sun.javadoc.RootDoc;
+import com.sun.javadoc.SourcePosition;
+import java.util.ArrayList;
+import java.util.List;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.NestingKind;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
+import jdk.javadoc.doclet.DocletEnvironment;
+
+/**
+ * The {@code RootDocImpl} is an implementation of the "old" Doclet APIs (previously under
+ * {@code com.sun.javadoc.*}, deprecated since 9 and removed in 13) in terms of new Doclet APIs
+ * {@link jdk.javadoc.doclet.Doclet}. ({@link DocletEnvironment}).
+ */
+public class RootDocImpl extends DocImpl<Element> implements RootDoc {
+
+    private ClassDoc[] classes;
+
+    public RootDocImpl(DocletEnvironment environment) {
+        super(null, new Context(environment));
+
+        for (var e : environment.getSpecifiedElements()) {
+            switch (e.getKind()) {
+                case CLASS, INTERFACE, ENUM, ANNOTATION_TYPE -> addClass((TypeElement) e);
+                case PACKAGE -> PackageDocImpl.create((PackageElement) e, context);
+                case RECORD -> throw new UnsupportedOperationException(
+                        "records are not yet supported.");
+                case MODULE -> throw new UnsupportedOperationException(
+                        "modules are not yet supported.");
+                default -> throw new UnsupportedOperationException(
+                        "Not yet supported top-level TypeElement kind:" + e.getKind());
+            }
+        }
+    }
+
+    private void addClass(TypeElement c) {
+        switch (c.getKind()) {
+            case CLASS, ENUM, INTERFACE -> ClassDocImpl.create(c, context);
+            case ANNOTATION_TYPE -> AnnotationTypeDocImpl.create(c, context);
+            default -> throw new UnsupportedOperationException(
+                    "Unexpected element kind:" + c.getKind());
+        }
+        // Initialize nested
+        // TODO: Need to ensure this is needed!
+        ElementFilter.typesIn(c.getEnclosedElements())
+                .stream()
+                .filter(te -> te.getNestingKind() == NestingKind.MEMBER)
+                .forEach(te -> {
+                    if (te.getKind() == ElementKind.ANNOTATION_TYPE) {
+                        AnnotationTypeDocImpl.create(te, context);
+                    } else {
+                        ClassDocImpl.create(te, context);
+                    }
+                });
+    }
+
+    @Override
+    @Unused
+    public String[][] options() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused
+    public PackageDoc[] specifiedPackages() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused
+    public ClassDoc[] specifiedClasses() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc[] classes() {
+        if (classes == null) {
+            List<ClassDoc> classesAndAnnotations = new ArrayList<>(context.caches.classes.values());
+            classesAndAnnotations.addAll(context.caches.annotations.values());
+            classes = classesAndAnnotations.toArray(ClassDoc[]::new);
+        }
+        return classes;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc classNamed(String qualifiedName) {
+        TypeElement cls = context.environment.getElementUtils().getTypeElement(qualifiedName);
+        return cls == null ? null : ClassDocImpl.create(cls, context);
+    }
+
+    @Override
+    @Used(implemented = true)
+    public PackageDoc packageNamed(String name) {
+        for (PackageDoc pkg : context.caches.packages.values()) {
+            if (pkg.name().equals(name)) {
+                return pkg;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String name() {
+        return "*! Doclava !*";
+    }
+
+    @Override
+    public String qualifiedName() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isIncluded() {
+        return false;
+    }
+
+    @Override
+    @Unused
+    public void printError(String msg) {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused
+    public void printError(SourcePosition pos, String msg) {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused
+    public void printWarning(String msg) {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused
+    public void printWarning(SourcePosition pos, String msg) {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused
+    public void printNotice(String msg) {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused
+    public void printNotice(SourcePosition pos, String msg) {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/SeeTagImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/SeeTagImpl.java
new file mode 100644
index 0000000..c98d04e
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/SeeTagImpl.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.sun.javadoc.MemberDoc;
+import com.sun.javadoc.PackageDoc;
+import com.sun.javadoc.SeeTag;
+import com.sun.source.doctree.DocTree;
+import com.sun.source.doctree.DocTree.Kind;
+import com.sun.source.doctree.ReferenceTree;
+import com.sun.source.doctree.SeeTree;
+import java.util.HashMap;
+import java.util.stream.Collectors;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+
+class SeeTagImpl extends TagImpl implements SeeTag {
+
+    private final SeeTree seeTree;
+
+    protected SeeTagImpl(SeeTree seeTree, Element owner, Context context) {
+        super(seeTree, owner, context);
+
+        this.seeTree = seeTree;
+    }
+
+    static SeeTagImpl create(SeeTree docTree, Element owner, Context context) {
+        var tagsOfElement = context.caches.tags.see.computeIfAbsent(owner,
+                el -> new HashMap<>());
+        return tagsOfElement.computeIfAbsent(docTree,
+                el -> new SeeTagImpl(el, owner, context));
+    }
+
+    private String label;
+
+    @Override
+    @Unused(implemented = true)
+    public String label() {
+        if (label == null) {
+            var children = seeTree.getReference();
+            label = children
+                    .stream()
+                    .map(DocTree::toString)
+                    .collect(Collectors.joining(" "));
+        }
+        return label;
+    }
+
+    private boolean referencedPackageInitialised;
+    private PackageDocImpl referencedPackage;
+
+    @Override
+    @Unused(implemented = true)
+    public PackageDoc referencedPackage() {
+        if (!referencedPackageInitialised) {
+            String signature = getReferenceSignature(seeTree);
+            if (signature != null) {
+                PackageElement pe =
+                        context.environment.getElementUtils().getPackageElement(signature);
+                if (pe != null) {
+                    referencedPackage = PackageDocImpl.create(pe, context);
+                }
+            }
+            referencedPackageInitialised = true;
+        }
+        return referencedPackage;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public String referencedClassName() {
+        var rc = referencedClass();
+        return rc.qualifiedName();
+    }
+
+    private boolean referencedClassInitialised;
+    private ClassDocImpl referencedClass;
+
+    @Override
+    @Unused(implemented = true)
+    public ClassDocImpl referencedClass() {
+        if (!referencedClassInitialised) {
+            String signature = getReferenceSignature(seeTree);
+            if (signature != null) {
+                TypeElement te = context.environment.getElementUtils().getTypeElement(signature);
+                if (te != null) {
+                    referencedClass = switch (te.getKind()) {
+                        case CLASS, ENUM, INTERFACE -> ClassDocImpl.create(te, context);
+                        case ANNOTATION_TYPE -> AnnotationTypeDocImpl.create(te, context);
+                        default -> throw new UnsupportedOperationException(te.getKind() +
+                                " is not yet supported");
+                    };
+                }
+            }
+            referencedClassInitialised = true;
+        }
+        return referencedClass;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public String referencedMemberName() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public MemberDoc referencedMember() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    /**
+     * Get the signature of a reference to a Java language element (which is in a form of {@link
+     * ReferenceTree}) of a given {@link SeeTree}. For cases when reference is anything but {@link
+     * ReferenceTree} (e.g. it could be quoted-string or HTML) – return {@code null}.
+     *
+     * @param seeTree tag
+     * @return signature of a reference, or {@code null} if it's not referencing to a Java language
+     * element.
+     */
+    private String getReferenceSignature(SeeTree seeTree) {
+        var children = seeTree.getReference();
+        if (children.size() >= 1) {
+            DocTree ref = children.get(0);
+            if (ref.getKind() == Kind.REFERENCE) {
+                var asReference = (ReferenceTree) ref;
+                return asReference.getSignature();
+            }
+        }
+        return null;
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/SerialFieldTagImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/SerialFieldTagImpl.java
new file mode 100644
index 0000000..1fbfa88
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/SerialFieldTagImpl.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.SerialFieldTag;
+import com.sun.source.doctree.SerialFieldTree;
+import java.util.HashMap;
+import javax.lang.model.element.Element;
+
+class SerialFieldTagImpl extends TagImpl implements SerialFieldTag, Comparable<Object> {
+
+    protected SerialFieldTagImpl(SerialFieldTree serialFieldTree, Element owner, Context context) {
+        super(serialFieldTree, owner, context);
+    }
+
+    static SerialFieldTagImpl create(SerialFieldTree serialFieldTree, Element owner,
+            Context context) {
+        var tagsOfElement = context.caches.tags.serialField
+                .computeIfAbsent(owner, el -> new HashMap<>());
+        return tagsOfElement.computeIfAbsent(serialFieldTree,
+                el -> new SerialFieldTagImpl(el, owner, context));
+    }
+
+    /**
+     * Return the serialziable field name.
+     */
+    @Override
+    @Unused
+    public String fieldName() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    /**
+     * Return the field type string.
+     */
+    @Override
+    public String fieldType() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    /**
+     * Return the ClassDocImpl for field type.
+     *
+     * @returns null if no ClassDocImpl for field type is visible from containingClass context.
+     */
+    @Override
+    @Unused
+    public ClassDoc fieldTypeDoc() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    /**
+     * Return the field comment. If there is no serialField comment, return javadoc comment of
+     * corresponding FieldDocImpl.
+     */
+    @Override
+    @Unused
+    public String description() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    /**
+     * Return the kind of this tag.
+     */
+    @Override
+    @Used(implemented = true)
+    public String kind() {
+        return "@serialField";
+    }
+
+    /**
+     * Convert this object to a string.
+     */
+    @Unused
+    public String toString() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    /**
+     * Compares this Object with the specified Object for order.  Returns a negative integer, zero,
+     * or a positive integer as this Object is less than, equal to, or greater than the given
+     * Object.
+     * <p>
+     * Included to make SerialFieldTagImpl items java.lang.Comparable.
+     *
+     * @param obj the <code>Object</code> to be compared.
+     * @return a negative integer, zero, or a positive integer as this Object is less than, equal
+     * to, or greater than the given Object.
+     * @throws ClassCastException the specified Object's type prevents it from being compared to
+     * this Object.
+     * @since 1.2
+     */
+    @Override
+    public int compareTo(Object obj) {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/SourcePositionImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/SourcePositionImpl.java
new file mode 100644
index 0000000..7813498
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/SourcePositionImpl.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.SourcePosition;
+import java.io.File;
+
+class SourcePositionImpl implements SourcePosition {
+
+    public static final SourcePositionImpl STUB = new SourcePositionImpl();
+
+    private final File file;
+
+    public SourcePositionImpl() {
+        this.file = new File(".");
+    }
+
+    @Override
+    @Used(implemented = true)
+    public File file() {
+        return file;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public int line() {
+        return 0;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public int column() {
+        return 0;
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/TagImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/TagImpl.java
new file mode 100644
index 0000000..2aea77e
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/TagImpl.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.Doc;
+import com.sun.javadoc.SourcePosition;
+import com.sun.javadoc.Tag;
+import com.sun.source.doctree.BlockTagTree;
+import com.sun.source.doctree.DocTree;
+import com.sun.source.doctree.DocTree.Kind;
+import com.sun.source.doctree.InlineTagTree;
+import com.sun.source.doctree.ParamTree;
+import com.sun.source.doctree.SeeTree;
+import com.sun.source.doctree.SerialFieldTree;
+import com.sun.source.doctree.ThrowsTree;
+import com.sun.source.util.SimpleDocTreeVisitor;
+import java.util.HashMap;
+import java.util.Objects;
+import javax.lang.model.element.Element;
+
+class TagImpl implements Tag {
+
+    protected final DocTree docTree;
+    protected final Element owner;
+    protected final Context context;
+
+    protected TagImpl(DocTree docTree, Element owner, Context context) {
+        this.docTree = docTree;
+        this.owner = owner;
+        this.context = context;
+    }
+
+    static TagImpl create(DocTree docTree, Element owner, Context context) {
+        return switch (docTree.getKind()) {
+            case SEE -> SeeTagImpl.create((SeeTree) docTree, owner, context);
+            case PARAM -> ParamTagImpl.create((ParamTree) docTree, owner, context);
+            case SERIAL_FIELD -> SerialFieldTagImpl.create((SerialFieldTree) docTree,
+                    owner, context);
+            case THROWS -> ThrowsTagImpl.create((ThrowsTree) docTree, owner, context);
+            default -> {
+                var tagsOfElement = context.caches.tags.generic.computeIfAbsent(owner,
+                        el -> new HashMap<>());
+                yield tagsOfElement.computeIfAbsent(docTree, el -> new TagImpl(el, owner,
+                        context));
+            }
+        };
+    }
+
+    private String name;
+
+    @Override
+    @Used(implemented = true)
+    public String name() {
+        if (name == null) {
+            name = "@" + NAME_VISITOR.visit(docTree, context);
+        }
+        return name;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public Doc holder() {
+        return context.obtain(owner);
+    }
+
+    private String kind;
+
+    @Override
+    @Used(implemented = true)
+    public String kind() {
+        if (kind == null) {
+            kind = "@" + remapKind(NAME_VISITOR.visit(docTree, context));
+        }
+        return kind;
+    }
+
+    static String remapKind(String name) {
+        Objects.requireNonNull(name);
+        return switch (name) {
+            case "exception" -> "throws";
+            case "link", "linkplain" -> "see";
+            case "serialData" -> "serial";
+            default -> name;
+        };
+    }
+
+    private String text;
+
+    @Override
+    @Used(implemented = true)
+    public String text() {
+        if (text == null) {
+            text = docTree.toString();
+        }
+        return text;
+    }
+
+    @Override
+    @Unused
+    public Tag[] inlineTags() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Unused
+    public Tag[] firstSentenceTags() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Used(implemented = true)
+    public SourcePosition position() {
+        return SourcePositionImpl.STUB;
+    }
+
+    private static final SimpleDocTreeVisitor<String, Context> NAME_VISITOR =
+            new SimpleDocTreeVisitor<>() {
+                @Override
+                protected String defaultAction(DocTree node, Context context) {
+                    if (node instanceof BlockTagTree bt) {
+                        return bt.getTagName();
+                    }
+                    if (node instanceof InlineTagTree it) {
+                        return it.getTagName();
+                    }
+                    if (node.getKind() == Kind.ERRONEOUS) {
+                        System.err.println("Malformed tag: " + node.toString());
+                        return "erroneous";
+                    }
+                    return node.getKind().toString().toLowerCase();
+                }
+            };
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/ThrowsTagImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ThrowsTagImpl.java
new file mode 100644
index 0000000..fb40697
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/ThrowsTagImpl.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.ThrowsTag;
+import com.sun.javadoc.Type;
+import com.sun.source.doctree.DocTree;
+import com.sun.source.doctree.ThrowsTree;
+import java.util.HashMap;
+import java.util.stream.Collectors;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+class ThrowsTagImpl extends TagImpl implements ThrowsTag {
+
+    private final ThrowsTree throwsTree;
+
+    protected ThrowsTagImpl(ThrowsTree throwsTree, Element owner, Context context) {
+        super(throwsTree, owner, context);
+
+        this.throwsTree = throwsTree;
+    }
+
+    static ThrowsTagImpl create(ThrowsTree throwsTree, Element owner, Context context) {
+        var tagsOfElement = context.caches.tags.throwz.computeIfAbsent(owner,
+                el -> new HashMap<>());
+        return tagsOfElement.computeIfAbsent(throwsTree,
+                el -> new ThrowsTagImpl(el, owner, context));
+    }
+
+    private boolean exceptionNameInitialised;
+    private String exceptionName;
+
+    @Override
+    @Used(implemented = true)
+    public String exceptionName() {
+        if (!exceptionNameInitialised) {
+            var ref = throwsTree.getExceptionName();
+            if (ref != null) {
+                String signature = ref.getSignature();
+                var lastDotPos = signature.lastIndexOf(".");
+                exceptionName = signature.substring(lastDotPos + 1);
+            }
+            exceptionNameInitialised = true;
+        }
+        return exceptionName;
+    }
+
+    private boolean exceptionCommentInitialised;
+    private String exceptionComment;
+
+    @Override
+    @Used(implemented = true)
+    public String exceptionComment() {
+        if (!exceptionCommentInitialised) {
+            var desc = throwsTree.getDescription();
+            if (desc != null) {
+                exceptionComment = desc.stream()
+                        .map(DocTree::toString)
+                        .collect(Collectors.joining(" "));
+            }
+            exceptionCommentInitialised = true;
+        }
+        return exceptionComment;
+    }
+
+    private boolean exceptionInitialised;
+    private ClassDocImpl exception;
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc exception() {
+        if (!exceptionInitialised) {
+            var ref = throwsTree.getExceptionName();
+            if (ref != null) {
+                String signature = ref.getSignature();
+                if (signature != null) {
+                    TypeElement te =
+                            context.environment.getElementUtils().getTypeElement(signature);
+                    if (te != null) {
+                        exception = ClassDocImpl.create(te, context);
+                    }
+                }
+            }
+            exceptionInitialised = true;
+        }
+        return exception;
+    }
+
+    @Override
+    @Unused
+    public Type exceptionType() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/TypeImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/TypeImpl.java
new file mode 100644
index 0000000..a7cf76b
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/TypeImpl.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.AnnotatedType;
+import com.sun.javadoc.AnnotationTypeDoc;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.ParameterizedType;
+import com.sun.javadoc.Type;
+import com.sun.javadoc.TypeVariable;
+import com.sun.javadoc.WildcardType;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ErrorType;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleTypeVisitor14;
+
+abstract class TypeImpl implements Type {
+
+    protected final TypeMirror typeMirror;
+    protected final Context context;
+
+    protected TypeImpl(TypeMirror typeMirror, Context context) {
+        this.typeMirror = typeMirror;
+        this.context = context;
+    }
+
+    protected static Type create(TypeMirror m, Context context) {
+         return create(m, context, /* underlyingType= */ false);
+    }
+
+    protected static Type create(TypeMirror m, Context context, boolean underlyingType) {
+        return switch (m.getKind()) {
+            // primitive types
+            case BOOLEAN -> PrimitiveTypeImpl.BOOLEAN;
+            case BYTE -> PrimitiveTypeImpl.BYTE;
+            case CHAR -> PrimitiveTypeImpl.CHAR;
+            case DOUBLE -> PrimitiveTypeImpl.DOUBLE;
+            case FLOAT -> PrimitiveTypeImpl.FLOAT;
+            case INT -> PrimitiveTypeImpl.INT;
+            case LONG -> PrimitiveTypeImpl.LONG;
+            case SHORT -> PrimitiveTypeImpl.SHORT;
+            // void is also a "primitive type"
+            case VOID -> PrimitiveTypeImpl.VOID;
+            case NULL -> PrimitiveTypeImpl.NULL;
+            // arrays
+            case ARRAY -> {
+                yield ArrayTypeImpl.create((ArrayType) m, context);
+            }
+            // complex types
+            case WILDCARD -> {
+                var wildcardType = (javax.lang.model.type.WildcardType) m;
+                yield WildcardTypeImpl.create(wildcardType, context);
+            }
+            case TYPEVAR -> {
+                var typeVar = (javax.lang.model.type.TypeVariable) m;
+                yield TypeVariableImpl.create(typeVar, context);
+            }
+            case DECLARED -> {
+                var dt = (DeclaredType) m;
+                // Order matters! AnnotatedTypeImpl goes first as it has an "underlying type"
+                // which will be constructed by this method in create() routine.
+                if (!underlyingType && !dt.getAnnotationMirrors().isEmpty()) {
+                    yield AnnotatedTypeImpl.create(dt, context);
+                }
+                if (!dt.getTypeArguments().isEmpty()) {
+                    yield ParameterizedTypeImpl.create(dt, context);
+                }
+                //TODO: check that it will cast.
+                var el = (TypeElement) dt.asElement();
+                if (el.getKind() == ElementKind.ANNOTATION_TYPE) {
+                    yield AnnotationTypeDocImpl.create(el, context);
+                }
+                yield ClassDocImpl.create(el, context);
+            }
+            case NONE -> {
+                // e.g. Object.superclass()
+                yield null;
+            }
+            case ERROR -> {
+                var errorType = (ErrorType) m;
+                var el = (TypeElement) errorType.asElement();
+                if (el.getKind() == ElementKind.ANNOTATION_TYPE) {
+                    yield AnnotationTypeDocImpl.create(el, context);
+                }
+                yield ErrorTypeImpl.create(errorType, context);
+            }
+            default -> throw new IllegalArgumentException(
+                    "Unexpected type of kind: " + m.getKind());
+        };
+    }
+
+    @Override
+    @Unused
+    public String typeName() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Used(implemented = false) // Not all cases covered yet in QUALIFIED_NAME_VISITOR
+    public String qualifiedTypeName() {
+        return QUALIFIED_NAME_VISITOR.visit(typeMirror, context);
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public Type getElementType() {
+        return null;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String simpleTypeName() {
+        var qualifiedTypeName = QUALIFIED_NAME_VISITOR.visit(typeMirror, context);
+        return qualifiedTypeName.substring(qualifiedTypeName.lastIndexOf('.') + 1);
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String dimension() {
+        return "";
+    }
+
+    @Override
+    @Used(implemented = true)
+    public boolean isPrimitive() {
+        return false;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc asClassDoc() {
+        return null;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public TypeVariable asTypeVariable() {
+        return null;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public WildcardType asWildcardType() {
+        return null;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ParameterizedType asParameterizedType() {
+        return null;
+    }
+
+    @Override
+    @Unused(implemented = true)
+    public AnnotationTypeDoc asAnnotationTypeDoc() {
+        return null;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public AnnotatedType asAnnotatedType() {
+        return null;
+    }
+
+    private static final SimpleTypeVisitor14<String, Context> QUALIFIED_NAME_VISITOR = new SimpleTypeVisitor14<>() {
+        @Override
+        public String visitPrimitive(PrimitiveType t, Context context) {
+            return switch (t.getKind()) {
+                case BOOLEAN -> "boolean";
+                case BYTE -> "byte";
+                case CHAR -> "char";
+                case DOUBLE -> "double";
+                case FLOAT -> "float";
+                case INT -> "int";
+                case LONG -> "long";
+                case SHORT -> "short";
+                default -> throw new IllegalArgumentException("Unexpected primitive type with "
+                        + "kind: " + t.getKind());
+            };
+        }
+
+        @Override
+        public String visitTypeVariable(javax.lang.model.type.TypeVariable t, Context context) {
+            return t.asElement().toString();
+        }
+
+        @Override
+        public String visitDeclared(DeclaredType t, Context context) {
+            final String typeName = t.asElement().toString();
+
+            if (typeName.contains("<")) {
+                throw new RuntimeException();
+            }
+
+            return typeName;
+        }
+
+        @Override
+        public String visitArray(ArrayType t, Context context) {
+            return this.visit(t.getComponentType(), context);
+        }
+
+        @Override
+        public String visitWildcard(javax.lang.model.type.WildcardType t, Context context) {
+            //TODO: hack
+            return "?";
+            //return super.visitWildcard(t, context);
+        }
+
+        @Override
+        protected String defaultAction(TypeMirror e, Context context) {
+            throw new UnsupportedOperationException(
+                    "Name visitor is not yet implemented for " + e.getKind());
+        }
+    };
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/TypeVariableImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/TypeVariableImpl.java
new file mode 100644
index 0000000..5695ce5
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/TypeVariableImpl.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.AnnotationDesc;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.ProgramElementDoc;
+import com.sun.javadoc.Type;
+import com.sun.javadoc.TypeVariable;
+import java.util.Objects;
+import java.util.stream.Stream;
+import javax.lang.model.type.IntersectionType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleTypeVisitor8;
+
+class TypeVariableImpl extends TypeImpl implements TypeVariable {
+
+    private final javax.lang.model.type.TypeVariable typeVariable;
+    private Type[] bounds;
+
+    protected TypeVariableImpl(javax.lang.model.type.TypeVariable typeVariable, Context context) {
+        super(typeVariable, context);
+        this.typeVariable = typeVariable;
+    }
+
+    static TypeVariableImpl create(javax.lang.model.type.TypeVariable typeVariable,
+            Context context) {
+        return context.caches.types.typevar.computeIfAbsent(typeVariable,
+                el -> new TypeVariableImpl(typeVariable, context));
+    }
+
+    @Override
+    @Used(implemented = true)
+    public Type[] bounds() {
+        if (bounds == null) {
+            TypeMirror bound = typeVariable.getUpperBound();
+            bounds = bound.accept(new SimpleTypeVisitor8<Stream<? extends TypeMirror>, Void>(Stream.of(bound)) {
+                        @Override
+                        public Stream<? extends TypeMirror> visitIntersection(IntersectionType t, Void o) {
+                            return t.getBounds().stream();
+                        }
+                    }, null)
+                    .map(typeMirror -> TypeImpl.create(typeMirror, context))
+                    .filter(type -> !type.qualifiedTypeName().equals("java.lang.Object"))
+                    .toArray(Type[]::new);
+        }
+        return bounds;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc asClassDoc() {
+        TypeMirror erasure = context.environment.getTypeUtils().erasure(typeVariable);
+        Type type = create(erasure, context);
+        Objects.requireNonNull(type);
+        return type.asClassDoc();
+    }
+
+    @Override
+    @Unused
+    public ProgramElementDoc owner() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Used(implemented = true)
+    public TypeVariable asTypeVariable() {
+        return this;
+    }
+
+    @Override
+    @Unused
+    public AnnotationDesc[] annotations() {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    @Used(implemented = true)
+    public String typeName() {
+        TypeMirror erasure = context.environment.getTypeUtils().erasure(typeVariable);
+        Type type = create(erasure, context);
+        return type.typeName();
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/google/doclava/javadoc/WildcardTypeImpl.java b/doclet_adapter/src/main/java/com/google/doclava/javadoc/WildcardTypeImpl.java
new file mode 100644
index 0000000..077a70e
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/google/doclava/javadoc/WildcardTypeImpl.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.google.doclava.javadoc;
+
+import com.google.doclava.annotation.Used;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.Type;
+import java.util.Objects;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.WildcardType;
+
+class WildcardTypeImpl extends TypeImpl implements com.sun.javadoc.WildcardType {
+
+    private final WildcardType wildcardType;
+
+    protected WildcardTypeImpl(WildcardType wildcardType, Context context) {
+        super(wildcardType, context);
+        this.wildcardType = wildcardType;
+    }
+
+    static WildcardTypeImpl create(WildcardType wildcardType, Context context) {
+        return context.caches.types.wildcard.computeIfAbsent(wildcardType,
+                el -> new WildcardTypeImpl(wildcardType, context));
+    }
+
+    @Override
+    @Used(implemented = true)
+    public ClassDoc asClassDoc() {
+        TypeMirror erasure = context.environment.getTypeUtils().erasure(wildcardType);
+        Type type = create(erasure, context);
+        Objects.requireNonNull(type);
+        return type.asClassDoc();
+    }
+
+    @Override
+    @Used(implemented = true)
+    public com.sun.javadoc.WildcardType asWildcardType() {
+        return this;
+    }
+
+    @Override
+    @Used(implemented = true)
+    public Type[] extendsBounds() {
+        TypeMirror extendsBound = wildcardType.getExtendsBound();
+        if (extendsBound == null) {
+            return new Type[0];
+        }
+        return new Type[]{TypeImpl.create(extendsBound, context)};
+    }
+
+    @Override
+    @Used(implemented = true)
+    public Type[] superBounds() {
+        TypeMirror superBounds = wildcardType.getSuperBound();
+        if (superBounds == null) {
+            return new Type[0];
+        }
+        return new Type[]{TypeImpl.create(superBounds, context)};
+    }
+
+
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/AnnotatedType.java b/doclet_adapter/src/main/java/com/sun/javadoc/AnnotatedType.java
new file mode 100644
index 0000000..a91eaac
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/AnnotatedType.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents an annotated type.
+ * For example:
+ * <pre>
+ *      {@code @NonNull String}
+ *      {@code @Positive int}
+ * </pre>
+ *
+ * @author Mahmood Ali
+ * @since 1.8
+ */
+public interface AnnotatedType extends Type {
+
+    @Unused
+    AnnotationDesc[] annotations();
+
+    @Used
+    Type underlyingType();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/AnnotationDesc.java b/doclet_adapter/src/main/java/com/sun/javadoc/AnnotationDesc.java
new file mode 100644
index 0000000..db4cd8a
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/AnnotationDesc.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents an annotation.
+ * An annotation associates a value with each element of an annotation type.
+ *
+ * @author Scott Seligman
+ * @since 1.5
+ */
+public interface AnnotationDesc {
+
+    /**
+     * Returns the annotation type of this annotation.
+     *
+     * @return the annotation type of this annotation.
+     */
+    @Used
+    AnnotationTypeDoc annotationType();
+
+    /**
+     * Returns this annotation's elements and their values.
+     * Only those explicitly present in the annotation are
+     * included, not those assuming their default values.
+     * Returns an empty array if there are none.
+     *
+     * @return this annotation's elements and their values.
+     */
+    @Used
+    ElementValuePair[] elementValues();
+
+    /**
+     * Check for the synthesized bit on the annotation.
+     *
+     * @return true if the annotation is synthesized.
+     */
+    @Unused
+    boolean isSynthesized();
+
+    /**
+     * Represents an association between an annotation type element
+     * and one of its values.
+     *
+     * @author Scott Seligman
+     * @since 1.5
+     */
+    interface ElementValuePair {
+
+        /**
+         * Returns the annotation type element.
+         *
+         * @return the annotation type element.
+         */
+        @Used
+        AnnotationTypeElementDoc element();
+
+        /**
+         * Returns the value associated with the annotation type element.
+         *
+         * @return the value associated with the annotation type element.
+         */
+        @Used
+        AnnotationValue value();
+    }
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/AnnotationTypeDoc.java b/doclet_adapter/src/main/java/com/sun/javadoc/AnnotationTypeDoc.java
new file mode 100644
index 0000000..e090eba
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/AnnotationTypeDoc.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents an annotation type.
+ *
+ * @author Scott Seligman
+ * @since 1.5
+ */
+public interface AnnotationTypeDoc extends ClassDoc {
+
+    /**
+     * Returns the elements of this annotation type.
+     * Returns an empty array if there are none.
+     *
+     * @return the elements of this annotation type.
+     */
+    @Used
+    AnnotationTypeElementDoc[] elements();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/AnnotationTypeElementDoc.java b/doclet_adapter/src/main/java/com/sun/javadoc/AnnotationTypeElementDoc.java
new file mode 100644
index 0000000..90536da
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/AnnotationTypeElementDoc.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents an element of an annotation type.
+ *
+ * @author Scott Seligman
+ * @since 1.5
+ */
+public interface AnnotationTypeElementDoc extends MethodDoc {
+
+    /**
+     * Returns the default value of this element.
+     * Returns null if this element has no default.
+     *
+     * @return the default value of this element.
+     */
+    @Used
+    AnnotationValue defaultValue();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/AnnotationValue.java b/doclet_adapter/src/main/java/com/sun/javadoc/AnnotationValue.java
new file mode 100644
index 0000000..2caef62
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/AnnotationValue.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents a value of an annotation type element.
+ *
+ * @author Scott Seligman
+ * @since 1.5
+ */
+public interface AnnotationValue {
+
+    /**
+     * Returns the value.
+     * The type of the returned object is one of the following:
+     * <ul><li> a wrapper class for a primitive type
+     *     <li> <code>String</code>
+     *     <li> <code>Type</code> (representing a class literal)
+     *     <li> <code>FieldDoc</code> (representing an enum constant)
+     *     <li> <code>AnnotationDesc</code>
+     *     <li> <code>AnnotationValue[]</code>
+     * </ul>
+     *
+     * @return the value.
+     */
+    @Used
+    Object value();
+
+    /**
+     * Returns a string representation of the value.
+     *
+     * @return the text of a Java language annotation value expression
+     *          whose value is the value of this element.
+     */
+    @Unused
+    String toString();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/ClassDoc.java b/doclet_adapter/src/main/java/com/sun/javadoc/ClassDoc.java
new file mode 100644
index 0000000..8318feb
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/ClassDoc.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents a java class or interface and provides access to
+ * information about the class, the class's comment and tags, and the
+ * members of the class.  A ClassDoc only exists if it was
+ * processed in this run of javadoc.  References to classes
+ * which may or may not have been processed in this run are
+ * referred to using Type (which can be converted to ClassDoc,
+ * if possible).
+ *
+ * @see Type
+ *
+ * @since 1.2
+ * @author Kaiyang Liu (original)
+ * @author Robert Field (rewrite)
+ */
+public interface ClassDoc extends ProgramElementDoc, Type {
+
+    /**
+     * Return true if this class is abstract.  Return true
+     * for all interfaces.
+     */
+    @Used
+    boolean isAbstract();
+
+    /**
+     * Return true if this class implements or interface extends
+     * <code>java.io.Serializable</code>.
+     *
+     * Since <code>java.io.Externalizable</code> extends
+     * <code>java.io.Serializable</code>,
+     * Externalizable objects are also Serializable.
+     */
+    @Unused
+    boolean isSerializable();
+
+    /**
+     * Return true if this class implements or interface extends
+     * <code>java.io.Externalizable</code>.
+     */
+    @Unused
+    boolean isExternalizable();
+
+    /**
+     * Return the serialization methods for this class or
+     * interface.
+     *
+     * @return an array of MethodDoc objects that represents
+     *         the serialization methods for this class or interface.
+     */
+    @Unused
+    MethodDoc[] serializationMethods();
+
+    /**
+     * Return the Serializable fields of this class or interface.
+     * <p>
+     * Return either a list of default fields documented by
+     * <code>serial</code> tag<br>
+     * or return a single <code>FieldDoc</code> for
+     * <code>serialPersistentField</code> member.
+     * There should be a <code>serialField</code> tag for
+     * each Serializable field defined by an <code>ObjectStreamField</code>
+     * array component of <code>serialPersistentField</code>.
+     *
+     * @return an array of <code>FieldDoc</code> objects for the Serializable
+     *         fields of this class or interface.
+     *
+     * @see #definesSerializableFields()
+     * @see SerialFieldTag
+     */
+    @Unused
+    FieldDoc[] serializableFields();
+
+    /**
+     *  Return true if Serializable fields are explicitly defined with
+     *  the special class member <code>serialPersistentFields</code>.
+     *
+     * @see #serializableFields()
+     * @see SerialFieldTag
+     */
+    @Unused
+    boolean definesSerializableFields();
+
+    /**
+     * Return the superclass of this class.  Return null if this is an
+     * interface.
+     *
+     * <p> <i>This method cannot accommodate certain generic type constructs.
+     * The <code>superclassType</code> method should be used instead.</i>
+     *
+     * @return the ClassDoc for the superclass of this class, null if
+     *         there is no superclass.
+     * @see #superclassType
+     */
+    @Used
+    ClassDoc superclass();
+
+    /**
+     * Return the superclass of this class.  Return null if this is an
+     * interface.  A superclass is represented by either a
+     * <code>ClassDoc</code> or a <code>ParametrizedType</code>.
+     *
+     * @return the superclass of this class, or null if there is no superclass.
+     * @since 1.5
+     */
+    @Used
+    Type superclassType();
+
+    /**
+     * Test whether this class is a subclass of the specified class.
+     * If this is an interface, return false for all classes except
+     * <code>java.lang.Object</code> (we must keep this unexpected
+     * behavior for compatibility reasons).
+     *
+     * @param cd the candidate superclass.
+     * @return true if cd is a superclass of this class.
+     */
+    @Unused
+    boolean subclassOf(ClassDoc cd);
+
+    /**
+     * Return interfaces implemented by this class or interfaces extended
+     * by this interface. Includes only directly-declared interfaces, not
+     * inherited interfaces.
+     * Return an empty array if there are no interfaces.
+     *
+     * <p> <i>This method cannot accommodate certain generic type constructs.
+     * The <code>interfaceTypes</code> method should be used instead.</i>
+     *
+     * @return an array of ClassDoc objects representing the interfaces.
+     * @see #interfaceTypes
+     */
+    @Unused
+    ClassDoc[] interfaces();
+
+    /**
+     * Return interfaces implemented by this class or interfaces extended
+     * by this interface. Includes only directly-declared interfaces, not
+     * inherited interfaces.
+     * Return an empty array if there are no interfaces.
+     *
+     * @return an array of interfaces, each represented by a
+     *         <code>ClassDoc</code> or a <code>ParametrizedType</code>.
+     * @since 1.5
+     */
+    @Used
+    Type[] interfaceTypes();
+
+    /**
+     * Return the formal type parameters of this class or interface.
+     * Return an empty array if there are none.
+     *
+     * @return the formal type parameters of this class or interface.
+     * @since 1.5
+     */
+    @Used
+    TypeVariable[] typeParameters();
+
+    /**
+     * Return the type parameter tags of this class or interface.
+     * Return an empty array if there are none.
+     *
+     * @return the type parameter tags of this class or interface.
+     * @since 1.5
+     */
+    @Unused
+    ParamTag[] typeParamTags();
+
+    /**
+     * Return
+     * <a href="{@docRoot}/com/sun/javadoc/package-summary.html#included">included</a>
+     * fields in this class or interface.
+     * Excludes enum constants if this is an enum type.
+     *
+     * @return an array of FieldDoc objects representing the included
+     *         fields in this class or interface.
+     */
+    @Unused
+    FieldDoc[] fields();
+
+    /**
+     * Return fields in this class or interface, filtered to the specified
+     * <a href="{@docRoot}/com/sun/javadoc/package-summary.html#included">access
+     * modifier option</a>.
+     * Excludes enum constants if this is an enum type.
+     *
+     * @param filter Specify true to filter according to the specified access
+     *               modifier option.
+     *               Specify false to include all fields regardless of
+     *               access modifier option.
+     * @return       an array of FieldDoc objects representing the included
+     *               fields in this class or interface.
+     */
+    @Used
+    FieldDoc[] fields(boolean filter);
+
+    /**
+     * Return the enum constants if this is an enum type.
+     * Return an empty array if there are no enum constants, or if
+     * this is not an enum type.
+     *
+     * @return the enum constants if this is an enum type.
+     */
+    @Used
+    FieldDoc[] enumConstants();
+
+    /**
+     * Return
+     * <a href="{@docRoot}/com/sun/javadoc/package-summary.html#included">included</a>
+     * methods in this class or interface.
+     * Same as <code>methods(true)</code>.
+     *
+     * @return an array of MethodDoc objects representing the included
+     *         methods in this class or interface.  Does not include
+     *         constructors or annotation type elements.
+     */
+    @Unused
+    MethodDoc[] methods();
+
+    /**
+     * Return methods in this class or interface, filtered to the specified
+     * <a href="{@docRoot}/com/sun/javadoc/package-summary.html#included">access
+     * modifier option</a>.  Does not include constructors or annotation
+     *          type elements.
+     *
+     * @param filter Specify true to filter according to the specified access
+     *               modifier option.
+     *               Specify false to include all methods regardless of
+     *               access modifier option.
+     * @return       an array of MethodDoc objects representing the included
+     *               methods in this class or interface.
+     */
+    @Used
+    MethodDoc[] methods(boolean filter);
+
+    /**
+     * Return
+     * <a href="{@docRoot}/com/sun/javadoc/package-summary.html#included">included</a>
+     * constructors in this class.  An array containing the default
+     * no-arg constructor is returned if no other constructors exist.
+     * Return empty array if this is an interface.
+     *
+     * @return an array of ConstructorDoc objects representing the included
+     *         constructors in this class.
+     */
+    @Unused
+    ConstructorDoc[] constructors();
+
+    /**
+     * Return constructors in this class, filtered to the specified
+     * <a href="{@docRoot}/com/sun/javadoc/package-summary.html#included">access
+     * modifier option</a>.  Return an array containing the default
+     * no-arg constructor if no other constructors exist.
+     *
+     * @param filter Specify true to filter according to the specified access
+     *               modifier option.
+     *               Specify false to include all constructors regardless of
+     *               access modifier option.
+     * @return       an array of ConstructorDoc objects representing the included
+     *               constructors in this class.
+     */
+    @Used
+    ConstructorDoc[] constructors(boolean filter);
+
+
+    /**
+     * Return
+     * <a href="{@docRoot}/com/sun/javadoc/package-summary.html#included">included</a>
+     * nested classes and interfaces within this class or interface.
+     * This includes both static and non-static nested classes.
+     * (This method should have been named <code>nestedClasses()</code>,
+     * as inner classes are technically non-static.)  Anonymous and local classes
+     * or interfaces are not included.
+     *
+     * @return an array of ClassDoc objects representing the included classes
+     *         and interfaces defined in this class or interface.
+     */
+    @Used
+    ClassDoc[] innerClasses();
+
+    /**
+     * Return nested classes and interfaces within this class or interface
+     * filtered to the specified
+     * <a href="{@docRoot}/com/sun/javadoc/package-summary.html#included">access
+     * modifier option</a>.
+     * This includes both static and non-static nested classes.
+     * Anonymous and local classes are not included.
+     *
+     * @param filter Specify true to filter according to the specified access
+     *               modifier option.
+     *               Specify false to include all nested classes regardless of
+     *               access modifier option.
+     * @return       a filtered array of ClassDoc objects representing the included
+     *               classes and interfaces defined in this class or interface.
+     */
+    @Used
+    ClassDoc[] innerClasses(boolean filter);
+
+    /**
+     * Find the specified class or interface within the context of this class doc.
+     * Search order: 1) qualified name, 2) nested in this class or interface,
+     * 3) in this package, 4) in the class imports, 5) in the package imports.
+     * Return the ClassDoc if found, null if not found.
+     */
+    @Used
+    ClassDoc findClass(String className);
+
+    /**
+     * Get the list of classes and interfaces declared as imported.
+     * These are called "single-type-import declarations" in
+     * <cite>The Java&trade; Language Specification</cite>.
+     *
+     * @return an array of ClassDoc representing the imported classes.
+     *
+     * @deprecated  Import declarations are implementation details that
+     *          should not be exposed here.  In addition, not all imported
+     *          classes are imported through single-type-import declarations.
+     */
+    @Deprecated
+    @Unused
+    ClassDoc[] importedClasses();
+
+    /**
+     * Get the list of packages declared as imported.
+     * These are called "type-import-on-demand declarations" in
+     * <cite>The Java&trade; Language Specification</cite>.
+     *
+     * @return an array of PackageDoc representing the imported packages.
+     *
+     * @deprecated  Import declarations are implementation details that
+     *          should not be exposed here.  In addition, this method's
+     *          return type does not allow for all type-import-on-demand
+     *          declarations to be returned.
+     */
+    @Deprecated
+    @Unused
+    PackageDoc[] importedPackages();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/ConstructorDoc.java b/doclet_adapter/src/main/java/com/sun/javadoc/ConstructorDoc.java
new file mode 100644
index 0000000..f7f115b
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/ConstructorDoc.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+/**
+ * Represents a constructor of a java class.
+ *
+ * @since 1.2
+ * @author Robert Field
+ */
+public interface ConstructorDoc extends ExecutableMemberDoc {
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/Doc.java b/doclet_adapter/src/main/java/com/sun/javadoc/Doc.java
new file mode 100644
index 0000000..18f7660
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/Doc.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import java.text.BreakIterator;
+import java.util.Locale;
+
+/**
+ * Represents Java language constructs (package, class, constructor,
+ * method, field) which have comments and have been processed by this
+ * run of javadoc.  All Doc objects are unique, that is, they
+ * are == comparable.
+ *
+ * @since 1.2
+ * @author Robert Field
+ * @author Scott Seligman (generics, enums, annotations)
+ */
+public interface Doc extends Comparable<Object> {
+
+    /**
+     * Return the text of the comment for this doc item.
+     * Tags have been removed.
+     */
+    @Unused
+    String commentText();
+
+    /**
+     * Return all tags in this Doc item.
+     *
+     * @return an array of {@link Tag} objects containing all tags on
+     *         this Doc item.
+     */
+    @Unused
+    Tag[] tags();
+
+    /**
+     * Return tags of the specified {@linkplain Tag#kind() kind} in
+     * this Doc item.
+     *
+     * For example, if 'tagname' has value "@serial", all tags in
+     * this Doc item of kind "@serial" will be returned.
+     *
+     * @param tagname name of the tag kind to search for.
+     * @return an array of Tag containing all tags whose 'kind()'
+     * matches 'tagname'.
+     */
+    @Unused
+    Tag[] tags(String tagname);
+
+    /**
+     * Return the see also tags in this Doc item.
+     *
+     * @return an array of SeeTag containing all @see tags.
+     */
+    @Unused
+    SeeTag[] seeTags();
+
+    /**
+     * Return comment as an array of tags. Includes inline tags
+     * (i.e. {&#64;link <i>reference</i>} tags)  but not
+     * block tags.
+     * Each section of plain text is represented as a {@link Tag}
+     * of {@linkplain Tag#kind() kind} "Text".
+     * Inline tags are represented as a {@link SeeTag} of kind "@see"
+     * and name "@link".
+     *
+     * @return an array of {@link Tag}s representing the comment
+     */
+    @Used
+    Tag[] inlineTags();
+
+    /**
+     * Return the first sentence of the comment as an array of tags.
+     * Includes inline tags
+     * (i.e. {&#64;link <i>reference</i>} tags)  but not
+     * block tags.
+     * Each section of plain text is represented as a {@link Tag}
+     * of {@linkplain Tag#kind() kind} "Text".
+     * Inline tags are represented as a {@link SeeTag} of kind "@see"
+     * and name "@link".
+     * <p>
+     * If the locale is English language, the first sentence is
+     * determined by the rules described in the Java Language
+     * Specification (first version): &quot;This sentence ends
+     * at the first period that is followed by a blank, tab, or
+     * line terminator or at the first tagline.&quot;, in
+     * addition a line will be terminated by block
+     * HTML tags: &lt;p&gt;  &lt;/p&gt;  &lt;h1&gt;
+     * &lt;h2&gt;  &lt;h3&gt; &lt;h4&gt;  &lt;h5&gt;  &lt;h6&gt;
+     * &lt;hr&gt;  &lt;pre&gt;  or &lt;/pre&gt;.
+     * If the locale is not English, the sentence end will be
+     * determined by
+     * {@link BreakIterator#getSentenceInstance(Locale)}.
+
+     * @return an array of {@link Tag}s representing the
+     * first sentence of the comment
+     */
+    @Unused
+    Tag[] firstSentenceTags();
+
+    /**
+     * Return the full unprocessed text of the comment.  Tags
+     * are included as text.  Used mainly for store and retrieve
+     * operations like internalization.
+     */
+    @Used
+    String getRawCommentText();
+
+    /**
+     * Set the full unprocessed text of the comment.  Tags
+     * are included as text.  Used mainly for store and retrieve
+     * operations like internalization.
+     */
+    @Unused
+    void setRawCommentText(String rawDocumentation);
+
+    /**
+     * Returns the non-qualified name of this Doc item.
+     *
+     * @return  the name
+     */
+    @Used
+    String name();
+
+    /**
+     * Compares this doc object with the specified object for order.  Returns a
+     * negative integer, zero, or a positive integer as this doc object is less
+     * than, equal to, or greater than the given object.
+     * <p>
+     * This method satisfies the {@link java.lang.Comparable} interface.
+     *
+     * @param   obj  the <code>Object</code> to be compared.
+     * @return  a negative integer, zero, or a positive integer as this Object
+     *      is less than, equal to, or greater than the given Object.
+     * @exception ClassCastException the specified Object's type prevents it
+     *        from being compared to this Object.
+     */
+    int compareTo(Object obj);
+
+    /**
+     * Is this Doc item a field (but not an enum constant)?
+     *
+     * @return true if it represents a field
+     */
+    @Unused
+    boolean isField();
+
+    /**
+     * Is this Doc item an enum constant?
+     *
+     * @return true if it represents an enum constant
+     * @since 1.5
+     */
+    @Unused
+    boolean isEnumConstant();
+
+    /**
+     * Is this Doc item a constructor?
+     *
+     * @return true if it represents a constructor
+     */
+    @Unused
+    boolean isConstructor();
+
+    /**
+     * Is this Doc item a method (but not a constructor or annotation
+     * type element)?
+     *
+     * @return true if it represents a method
+     */
+    @Unused
+    boolean isMethod();
+
+    /**
+     * Is this Doc item an annotation type element?
+     *
+     * @return true if it represents an annotation type element
+     * @since 1.5
+     */
+    @Used
+    boolean isAnnotationTypeElement();
+
+    /**
+     * Is this Doc item an interface (but not an annotation type)?
+     *
+     * @return true if it represents an interface
+     */
+    @Used
+    boolean isInterface();
+
+    /**
+     * Is this Doc item an exception class?
+     *
+     * @return true if it represents an exception
+     */
+    @Used
+    boolean isException();
+
+    /**
+     * Is this Doc item an error class?
+     *
+     * @return true if it represents a error
+     */
+    @Used
+    boolean isError();
+
+    /**
+     * Is this Doc item an enum type?
+     *
+     * @return true if it represents an enum type
+     * @since 1.5
+     */
+    @Used
+    boolean isEnum();
+
+    /**
+     * Is this Doc item an annotation type?
+     *
+     * @return true if it represents an annotation type
+     * @since 1.5
+     */
+    @Unused
+    boolean isAnnotationType();
+
+    /**
+     * Is this Doc item an
+     * <a href="{@docRoot}/com/sun/javadoc/package-summary.html#class">ordinary
+     * class</a>?
+     * (i.e. not an interface, annotation type, enum, exception, or error)?
+     *
+     * @return true if it represents an ordinary class
+     */
+    @Used
+    boolean isOrdinaryClass();
+
+    /**
+     * Is this Doc item a
+     * <a href="{@docRoot}/com/sun/javadoc/package-summary.html#class">class</a>
+     * (and not an interface or annotation type)?
+     * This includes ordinary classes, enums, errors and exceptions.
+     *
+     * @return true if it represents a class
+     */
+    @Unused
+    boolean isClass();
+
+    /**
+     * Return true if this Doc item is
+     * <a href="{@docRoot}/com/sun/javadoc/package-summary.html#included">included</a>
+     * in the result set.
+     */
+    @Used
+    boolean isIncluded();
+
+    /**
+     * Return the source position of the first line of the
+     * corresponding declaration, or null if
+     * no position is available.  A default constructor returns
+     * null because it has no location in the source file.
+     *
+     * @since 1.4
+     */
+    @Used
+    SourcePosition position();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/DocErrorReporter.java b/doclet_adapter/src/main/java/com/sun/javadoc/DocErrorReporter.java
new file mode 100644
index 0000000..1ce0404
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/DocErrorReporter.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Unused;
+
+/**
+ * This interface provides error, warning and notice printing.
+ *
+ * @since 1.2
+ * @author Robert Field
+ */
+public interface DocErrorReporter {
+
+    /**
+     * Print error message and increment error count.
+     *
+     * @param msg message to print
+     */
+    @Unused
+    void printError(String msg);
+
+    /**
+     * Print an error message and increment error count.
+     *
+     * @param pos the position item where the error occurs
+     * @param msg message to print
+     * @since 1.4
+     */
+    @Unused
+    void printError(SourcePosition pos, String msg);
+
+    /**
+     * Print warning message and increment warning count.
+     *
+     * @param msg message to print
+     */
+    @Unused
+    void printWarning(String msg);
+
+    /**
+     * Print warning message and increment warning count.
+     *
+     * @param pos the position item where the warning occurs
+     * @param msg message to print
+     * @since 1.4
+     */
+    @Unused
+    void printWarning(SourcePosition pos, String msg);
+
+    /**
+     * Print a message.
+     *
+     * @param msg message to print
+     */
+    @Unused
+    void printNotice(String msg);
+
+    /**
+     * Print a message.
+     *
+     * @param pos the position item where the message occurs
+     * @param msg message to print
+     * @since 1.4
+     */
+    @Unused
+    void printNotice(SourcePosition pos, String msg);
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/ExecutableMemberDoc.java b/doclet_adapter/src/main/java/com/sun/javadoc/ExecutableMemberDoc.java
new file mode 100644
index 0000000..61de275
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/ExecutableMemberDoc.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents a method or constructor of a java class.
+ *
+ * @since 1.2
+ * @author Robert Field
+ */
+public interface ExecutableMemberDoc extends MemberDoc {
+
+    /**
+     * Return exceptions this method or constructor throws.
+     * If the type of the exception is a type variable, return the
+     * <code>ClassDoc</code> of its erasure.
+     *
+     * <p> <i>The <code>thrownExceptions</code> method cannot
+     * accommodate certain generic type constructs.  The
+     * <code>thrownExceptionTypes</code> method should be used
+     * instead.</i>
+     *
+     * @return an array of ClassDoc[] representing the exceptions
+     *         thrown by this method.
+     * @see #thrownExceptionTypes
+     */
+    @Used
+    ClassDoc[] thrownExceptions();
+
+    /**
+     * Return exceptions this method or constructor throws.
+     *
+     * @return an array representing the exceptions thrown by this method.
+     *         Each array element is either a <code>ClassDoc</code> or a
+     *         <code>TypeVariable</code>.
+     * @since 1.5
+     */
+    @Unused
+    Type[] thrownExceptionTypes();
+
+    /**
+     * Return true if this method is native
+     */
+    @Used
+    boolean isNative();
+
+    /**
+     * Return true if this method is synchronized
+     */
+    @Used
+    boolean isSynchronized();
+
+    /**
+     * Return true if this method was declared to take a variable number
+     * of arguments.
+     *
+     * @since 1.5
+     */
+    @Used
+    boolean isVarArgs();
+
+    /**
+     * Get argument information.
+     *
+     * @see Parameter
+     *
+     * @return an array of Parameter, one element per argument
+     * in the order the arguments are present.
+     */
+    @Used
+    Parameter[] parameters();
+
+    /**
+     * Get the receiver type of this executable element.
+     *
+     * @return the receiver type of this executable element.
+     * @since 1.8
+     */
+    @Unused
+    Type receiverType();
+
+    /**
+     * Return the throws tags in this method.
+     *
+     * @return an array of ThrowTag containing all <code>&#64;exception</code>
+     * and <code>&#64;throws</code> tags.
+     */
+    @Unused
+    ThrowsTag[] throwsTags();
+
+    /**
+     * Return the param tags in this method, excluding the type
+     * parameter tags.
+     *
+     * @return an array of ParamTag containing all <code>&#64;param</code> tags
+     * corresponding to the parameters of this method.
+     */
+    @Unused
+    ParamTag[] paramTags();
+
+    /**
+     * Return the type parameter tags in this method.
+     *
+     * @return an array of ParamTag containing all <code>&#64;param</code> tags
+     * corresponding to the type parameters of this method.
+     * @since 1.5
+     */
+    @Unused
+    ParamTag[] typeParamTags();
+
+    /**
+     * Get the signature. It is the parameter list, type is qualified.
+     *      For instance, for a method <code>mymethod(String x, int y)</code>,
+     *      it will return <code>(java.lang.String,int)</code>.
+     */
+    @Used
+    String signature();
+
+    /**
+     * get flat signature.  all types are not qualified.
+     *      return a String, which is the flat signiture of this member.
+     *      It is the parameter list, type is not qualified.
+     *      For instance, for a method <code>mymethod(String x, int y)</code>,
+     *      it will return <code>(String, int)</code>.
+     */
+    @Used
+    String flatSignature();
+
+    /**
+     * Return the formal type parameters of this method or constructor.
+     * Return an empty array if this method or constructor is not generic.
+     *
+     * @return the formal type parameters of this method or constructor.
+     * @since 1.5
+     */
+    @Used
+    TypeVariable[] typeParameters();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/FieldDoc.java b/doclet_adapter/src/main/java/com/sun/javadoc/FieldDoc.java
new file mode 100644
index 0000000..6d8dd9b
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/FieldDoc.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents a field in a java class.
+ *
+ * @see MemberDoc
+ *
+ * @since 1.2
+ * @author Robert Field
+ */
+public interface FieldDoc extends MemberDoc {
+
+    /**
+     * Get type of this field.
+     */
+    @Used
+    Type type();
+
+    /**
+     * Return true if this field is transient
+     */
+    @Used
+    boolean isTransient();
+
+    /**
+     * Return true if this field is volatile
+     */
+    @Used
+    boolean isVolatile();
+
+    /**
+     * Return the serialField tags in this FieldDoc item.
+     *
+     * @return an array of <tt>SerialFieldTag</tt> objects containing
+     *         all <code>@serialField</code> tags.
+     */
+    @Unused
+    SerialFieldTag[] serialFieldTags();
+
+    /**
+     * Get the value of a constant field.
+     *
+     * @return the value of a constant field. The value is
+     * automatically wrapped in an object if it has a primitive type.
+     * If the field is not constant, returns null.
+     */
+    @Used
+    Object constantValue();
+
+    /**
+     * Get the value of a constant field.
+     *
+     * @return the text of a Java language expression whose value
+     * is the value of the constant. The expression uses no identifiers
+     * other than primitive literals. If the field is
+     * not constant, returns null.
+     */
+    @Unused
+    String constantValueExpression();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/MemberDoc.java b/doclet_adapter/src/main/java/com/sun/javadoc/MemberDoc.java
new file mode 100644
index 0000000..3be364e
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/MemberDoc.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents a member of a java class: field, constructor, or method.
+ * This is an abstract class dealing with information common to
+ * method, constructor and field members. Class members of a class
+ * (innerclasses) are represented instead by ClassDoc.
+ *
+ * @see MethodDoc
+ * @see FieldDoc
+ * @see ClassDoc
+ *
+ * @author Kaiyang Liu (original)
+ * @author Robert Field (rewrite)
+ */
+public interface MemberDoc extends ProgramElementDoc {
+
+    /**
+     * Returns true if this member was synthesized by the compiler.
+     */
+    @Used
+    boolean isSynthetic();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/MethodDoc.java b/doclet_adapter/src/main/java/com/sun/javadoc/MethodDoc.java
new file mode 100644
index 0000000..eceaf40
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/MethodDoc.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents a method of a java class.
+ *
+ * @since 1.2
+ * @author Robert Field
+ */
+public interface MethodDoc extends ExecutableMemberDoc {
+
+    /**
+     * Return true if this method is abstract
+     */
+    @Used
+    boolean isAbstract();
+
+    /**
+     * Return true if this method is default
+     */
+    @Used
+    boolean isDefault();
+
+    /**
+     * Get return type.
+     *
+     * @return the return type of this method, null if it
+     * is a constructor.
+     */
+    @Used
+    Type returnType();
+
+    /**
+     * Return the class containing the method that this method overrides.
+     *
+     * <p> <i>The <code>overriddenClass</code> method cannot
+     * accommodate certain generic type constructs.  The
+     * <code>overriddenType</code> method should be used instead.</i>
+     *
+     * @return a ClassDoc representing the superclass
+     *         defining a method that this method overrides, or null if
+     *         this method does not override.
+     */
+    @Unused
+    ClassDoc overriddenClass();
+
+    /**
+     * Return the type containing the method that this method overrides.
+     * It may be a <code>ClassDoc</code> or a <code>ParameterizedType</code>.
+     *
+     * @return the supertype whose method is overridden, or null if this
+     *         method does not override another in a superclass
+     * @since 1.5
+     */
+    @Unused
+    Type overriddenType();
+
+    /**
+     * Return the method that this method overrides.
+     *
+     * @return a MethodDoc representing a method definition
+     * in a superclass this method overrides, null if
+     * this method does not override.
+     */
+    @Used
+    MethodDoc overriddenMethod();
+
+    /**
+     * Tests whether this method overrides another.
+     * The overridden method may be one declared in a superclass or
+     * a superinterface (unlike {@link #overriddenMethod()}).
+     *
+     * <p> When a non-abstract method overrides an abstract one, it is
+     * also said to <i>implement</i> the other.
+     *
+     * @param meth  the other method to examine
+     * @return <tt>true</tt> if this method overrides the other
+     * @since 1.5
+     */
+    @Unused
+    boolean overrides(MethodDoc meth);
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/PackageDoc.java b/doclet_adapter/src/main/java/com/sun/javadoc/PackageDoc.java
new file mode 100644
index 0000000..2a03ddd
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/PackageDoc.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents a java package.  Provides access to information
+ * about the package, the package's comment and tags, and the
+ * classes in the package.
+ * <p>
+ * Each method whose return type is an array will return an empty
+ * array (never null) when there are no objects in the result.
+ *
+ * @since 1.2
+ * @author Kaiyang Liu (original)
+ * @author Robert Field (rewrite)
+ */
+public interface PackageDoc extends Doc {
+
+    /**
+     * Get all classes and interfaces in the package, filtered to the specified
+     * <a href="{@docRoot}/com/sun/javadoc/package-summary.html#included">access
+     * modifier option</a>.
+     *
+     * @return       filtered classes and interfaces in this package
+     * @param filter Specifying true filters according to the specified access
+     *               modifier option.
+     *               Specifying false includes all classes and interfaces
+     *               regardless of access modifier option.
+     * @since 1.4
+     */
+    @Unused
+    ClassDoc[] allClasses(boolean filter);
+
+    /**
+     * Get all
+     * <a href="{@docRoot}/com/sun/javadoc/package-summary.html#included">included</a>
+     * classes and interfaces in the package.  Same as allClasses(true).
+     *
+     * @return all included classes and interfaces in this package.
+     */
+    @Unused
+    ClassDoc[] allClasses();
+
+    /**
+     * Get included
+     * <a href="{@docRoot}/com/sun/javadoc/package-summary.html#class">ordinary</a>
+     * classes (that is, exclude exceptions, errors, enums, interfaces, and
+     * annotation types)
+     * in this package.
+     *
+     * @return included ordinary classes in this package.
+     */
+    @Used
+    ClassDoc[] ordinaryClasses();
+
+    /**
+     * Get included Exception classes in this package.
+     *
+     * @return included Exceptions in this package.
+     */
+    @Used
+    ClassDoc[] exceptions();
+
+    /**
+     * Get included Error classes in this package.
+     *
+     * @return included Errors in this package.
+     */
+    @Used
+    ClassDoc[] errors();
+
+    /**
+     * Get included enum types in this package.
+     *
+     * @return included enum types in this package.
+     * @since 1.5
+     */
+    @Used
+    ClassDoc[] enums();
+
+    /**
+     * Get included interfaces in this package, omitting annotation types.
+     *
+     * @return included interfaces in this package.
+     */
+    @Used
+    ClassDoc[] interfaces();
+
+    /**
+     * Get included annotation types in this package.
+     *
+     * @return included annotation types in this package.
+     * @since 1.5
+     */
+    @Used
+    AnnotationTypeDoc[] annotationTypes();
+
+    /**
+     * Get the annotations of this package.
+     * Return an empty array if there are none.
+     *
+     * @return the annotations of this package.
+     * @since 1.5
+     */
+    @Unused
+    AnnotationDesc[] annotations();
+
+    /**
+     * Lookup a class or interface within this package.
+     *
+     * @return ClassDoc of found class or interface,
+     * or null if not found.
+     */
+    @Unused
+    ClassDoc findClass(String className);
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/ParamTag.java b/doclet_adapter/src/main/java/com/sun/javadoc/ParamTag.java
new file mode 100644
index 0000000..58c3ec7
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/ParamTag.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents an @param documentation tag.
+ * Stores the name and comment parts of the parameter tag.
+ * An @param tag may represent either a method or constructor parameter,
+ * or a type parameter.
+ *
+ * @author Robert Field
+ *
+ */
+public interface ParamTag extends Tag {
+
+    /**
+     * Return the name of the parameter or type parameter
+     * associated with this <code>ParamTag</code>.
+     * The angle brackets delimiting a type parameter are not part of
+     * its name.
+     *
+     * @return the parameter name.
+     */
+    @Used
+    String parameterName();
+
+    /**
+     * Return the parameter comment
+     * associated with this <code>ParamTag</code>.
+     *
+     * @return the parameter comment.
+     */
+    @Used
+    String parameterComment();
+
+    /**
+     * Return true if this <code>ParamTag</code> corresponds to a type
+     * parameter.  Return false if it corresponds to an ordinary parameter
+     * of a method or constructor.
+     *
+     * @return true if this <code>ParamTag</code> corresponds to a type
+     * parameter.
+     * @since 1.5
+     */
+    @Used
+    boolean isTypeParameter();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/Parameter.java b/doclet_adapter/src/main/java/com/sun/javadoc/Parameter.java
new file mode 100644
index 0000000..facfbab
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/Parameter.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+
+/**
+ * Parameter information.
+ * This includes a parameter type and parameter name.
+ *
+ * @author Robert Field
+ */
+public interface Parameter {
+
+    /**
+     * Get the type of this parameter.
+     */
+    @Used
+    Type type();
+
+    /**
+     * Get local name of this parameter.
+     * For example if parameter is the short 'index', returns "index".
+     */
+    @Used
+    String name();
+
+    /**
+     * Get type name of this parameter.
+     * For example if parameter is the short 'index', returns "short".
+     * <p>
+     * This method returns a complete string
+     * representation of the type, including the dimensions of arrays and
+     * the type arguments of parameterized types.  Names are qualified.
+     */
+    @Used
+    String typeName();
+
+    /**
+     * Returns a string representation of the parameter.
+     * <p>
+     * For example if parameter is the short 'index', returns "short index".
+     *
+     * @return type and parameter name of this parameter.
+     */
+    @Unused
+    String toString();
+
+    /**
+     * Get the annotations of this parameter.
+     * Return an empty array if there are none.
+     *
+     * @return the annotations of this parameter.
+     * @since 1.5
+     */
+    @Used
+    AnnotationDesc[] annotations();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/ParameterizedType.java b/doclet_adapter/src/main/java/com/sun/javadoc/ParameterizedType.java
new file mode 100644
index 0000000..1435175
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/ParameterizedType.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents an invocation of a generic class or interface.  For example,
+ * given the generic interface {@code List<E>}, possible invocations
+ * include:
+ * <pre>
+ *      {@code List<String>}
+ *      {@code List<T extends Number>}
+ *      {@code List<?>}
+ * </pre>
+ * A generic inner class {@code Outer<T>.Inner<S>} might be invoked as:
+ * <pre>
+ *      {@code Outer<Number>.Inner<String>}
+ * </pre>
+ *
+ * @author Scott Seligman
+ * @since 1.5
+ */
+public interface ParameterizedType extends Type {
+
+    /**
+     * Return the generic class or interface that declared this type.
+     *
+     * @return the generic class or interface that declared this type.
+     */
+    @Unused
+    ClassDoc asClassDoc();
+
+    /**
+     * Return the actual type arguments of this type.
+     * For a generic type that is nested within some other generic type
+     * (such as {@code Outer<T>.Inner<S>}),
+     * only the type arguments of the innermost type are included.
+     *
+     * @return the actual type arguments of this type.
+     */
+    @Used
+    Type[] typeArguments();
+
+    /**
+     * Return the class type that is a direct supertype of this one.
+     * This is the superclass of this type's declaring class,
+     * with type arguments substituted in.
+     * Return null if this is an interface type.
+     *
+     * <p> For example, if this parameterized type is
+     * {@code java.util.ArrayList<String>}, the result will be
+     * {@code java.util.AbstractList<String>}.
+     *
+     * @return the class type that is a direct supertype of this one.
+     */
+    @Unused
+    Type superclassType();
+
+    /**
+     * Return the interface types directly implemented by or extended by this
+     * parameterized type.
+     * These are the interfaces directly implemented or extended
+     * by this type's declaring class or interface,
+     * with type arguments substituted in.
+     * Return an empty array if there are no interfaces.
+     *
+     * <p> For example, the interface extended by
+     * {@code java.util.Set<String>} is {@code java.util.Collection<String>}.
+     *
+     * @return the interface types directly implemented by or extended by this
+     * parameterized type.
+     */
+    @Unused
+    Type[] interfaceTypes();
+
+    /**
+     * Return the type that contains this type as a member.
+     * Return null is this is a top-level type.
+     *
+     * <p> For example, the containing type of
+     * {@code AnInterface.Nested<Number>} is the <code>ClassDoc</code>
+     * representing {@code AnInterface}, and the containing type of
+     * {@code Outer<String>.Inner<Number>} is the
+     * <code>ParameterizedType</code> representing {@code Outer<String>}.
+     *
+     * @return the type that contains this type as a member.
+     */
+    @Unused
+    Type containingType();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/ProgramElementDoc.java b/doclet_adapter/src/main/java/com/sun/javadoc/ProgramElementDoc.java
new file mode 100644
index 0000000..f6f293b
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/ProgramElementDoc.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents a java program element: class, interface, field,
+ * constructor, or method.
+ * This is an abstract class dealing with information common to
+ * these elements.
+ *
+ * @see MemberDoc
+ * @see ClassDoc
+ *
+ * @author Robert Field
+ */
+public interface ProgramElementDoc extends Doc {
+
+    /**
+     * Get the containing class or interface of this program element.
+     *
+     * @return a ClassDoc for this element's containing class or interface.
+     * If this is a top-level class or interface, return null.
+     */
+    @Used
+    ClassDoc containingClass();
+
+    /**
+     * Get the package that this program element is contained in.
+     *
+     * @return a PackageDoc for this element containing package.
+     * If in the unnamed package, this PackageDoc will have the
+     * name "".
+     */
+    @Used
+    PackageDoc containingPackage();
+
+    /**
+     * Get the fully qualified name of this program element.
+     * For example, for the class <code>java.util.Hashtable</code>,
+     * return "java.util.Hashtable".
+     * <p>
+     * For the method <code>bar()</code> in class <code>Foo</code>
+     * in the unnamed package, return "Foo.bar".
+     *
+     * @return the qualified name of the program element as a String.
+     */
+    @Used
+    String qualifiedName();
+
+    /**
+     * Get the modifier specifier integer.
+     *
+     * @see java.lang.reflect.Modifier
+     */
+    @Unused
+    int modifierSpecifier();
+
+    /**
+     * Get modifiers string.
+     * For example, for:
+     * <pre>
+     *   public abstract int foo() { ... }
+     * </pre>
+     * return "public abstract".
+     * Annotations are not included.
+     */
+    @Unused
+    String modifiers();
+
+    /**
+     * Get the annotations of this program element.
+     * Return an empty array if there are none.
+     *
+     * @return the annotations of this program element.
+     * @since 1.5
+     */
+    @Used
+    AnnotationDesc[] annotations();
+
+    /**
+     * Return true if this program element is public.
+     */
+    @Used
+    boolean isPublic();
+
+    /**
+     * Return true if this program element is protected.
+     */
+    @Used
+    boolean isProtected();
+
+    /**
+     * Return true if this program element is private.
+     */
+    @Used
+    boolean isPrivate();
+
+    /**
+     * Return true if this program element is package private.
+     */
+    @Used
+    boolean isPackagePrivate();
+    /**
+     * Return true if this program element is static.
+     */
+    @Used
+    boolean isStatic();
+
+    /**
+     * Return true if this program element is final.
+     */
+    @Used
+    boolean isFinal();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/RootDoc.java b/doclet_adapter/src/main/java/com/sun/javadoc/RootDoc.java
new file mode 100644
index 0000000..fc09a95
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/RootDoc.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents the root of the program structure information
+ * for one run of javadoc.  From this root all other program
+ * structure information can be extracted.
+ * Also represents the command line information -- the
+ * packages, classes and options specified by the user.
+ *
+ * @since 1.2
+ * @author Robert Field
+ */
+public interface RootDoc extends Doc, DocErrorReporter {
+
+    /**
+     * Command line options.
+     * <p>
+     * For example, given:
+     * <pre>
+     *     javadoc -foo this that -bar other ...</pre>
+     *
+     * this method will return:
+     * <pre>
+     *      options()[0][0] = "-foo"
+     *      options()[0][1] = "this"
+     *      options()[0][2] = "that"
+     *      options()[1][0] = "-bar"
+     *      options()[1][1] = "other"</pre>
+     *
+     * @return an array of arrays of String.
+     */
+    @Unused
+    String[][] options();
+
+    /**
+     * Return the packages
+     * <a href="package-summary.html#included">specified</a>
+     * on the command line.
+     * If <code>-subpackages</code> and <code>-exclude</code> options
+     * are used, return all the non-excluded packages.
+     *
+     * @return packages specified on the command line.
+     */
+    @Unused
+    PackageDoc[] specifiedPackages();
+
+    /**
+     * Return the classes and interfaces
+     * <a href="package-summary.html#included">specified</a>
+     * as source file names on the command line.
+     *
+     * @return classes and interfaces specified on the command line.
+     */
+    @Unused
+    ClassDoc[] specifiedClasses();
+
+    /**
+     * Return the
+     * <a href="package-summary.html#included">included</a>
+      classes and interfaces in all packages.
+     *
+     * @return included classes and interfaces in all packages.
+     */
+    @Used
+    ClassDoc[] classes();
+
+    /**
+     * Return a PackageDoc for the specified package name.
+     *
+     * @param name package name
+     *
+     * @return a PackageDoc holding the specified package, null if
+     * this package is not referenced.
+     */
+    @Used
+    PackageDoc packageNamed(String name);
+
+    /**
+     * Return a ClassDoc for the specified class or interface name.
+     *
+     * @param qualifiedName
+     * <a href="package-summary.html#qualified">qualified</a>
+     * class or package name
+     *
+     * @return a ClassDoc holding the specified class, null if
+     * this class is not referenced.
+     */
+    @Used
+    ClassDoc classNamed(String qualifiedName);
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/SeeTag.java b/doclet_adapter/src/main/java/com/sun/javadoc/SeeTag.java
new file mode 100644
index 0000000..e0c8269
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/SeeTag.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 1998, 2002, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Unused;
+
+/**
+ * Represents a user-defined cross-reference to related documentation.
+ * The tag can reference a package, class or member, or can hold
+ * plain text.  (The plain text might be a reference
+ * to something not online, such as a printed book, or be a hard-coded
+ * HTML link.)  The reference can either be inline with the comment,
+ * using <code>&#123;@link}</code>, or a separate block comment,
+ * using <code>@see</code>.
+ * Method <code>name()</code> returns "@link" (no curly braces) or
+ * "@see", depending on the tag.
+ * Method <code>kind()</code> returns "@see" for both tags.
+ *
+ * @author Kaiyang Liu (original)
+ * @author Robert Field (rewrite)
+ * @author Atul M Dambalkar
+ *
+ */
+public interface SeeTag extends Tag {
+
+    /**
+     * Get the label of the <code>@see</code> tag.
+     * Return null if no label is present.
+     * For example, for:
+     * <p>
+     *    &nbsp;&nbsp;<code>@see String#trim() the trim method</code>
+     * </p>
+     * return "the trim method".
+     */
+    @Unused
+    String label();
+
+    /**
+     * Get the package doc when <code>@see</code> references only a package.
+     * Return null if the package cannot be found, or if
+     * <code>@see</code> references any other element (class,
+     * interface, field, constructor, method) or non-element.
+     * For example, for:
+     * <p>
+     *   &nbsp;&nbsp;<code>@see java.lang</code>
+     * </p>
+     * return the <code>PackageDoc</code> for <code>java.lang</code>.
+     */
+    @Unused
+    PackageDoc referencedPackage();
+
+    /**
+     * Get the class or interface name of the <code>@see</code> reference.
+     * The name is fully qualified if the name specified in the
+     * original <code>@see</code> tag was fully qualified, or if the class
+     * or interface can be found; otherwise it is unqualified.
+     * If <code>@see</code> references only a package name, then return
+     * the package name instead.
+     * For example, for:
+     * <p>
+     *   &nbsp;&nbsp;<code>@see String#valueOf(java.lang.Object)</code>
+     * </p>
+     * return "java.lang.String".
+     * For "<code>@see java.lang</code>", return "java.lang".
+     * Return null if <code>@see</code> references a non-element, such as
+     * <code>@see &lt;a href="java.sun.com"&gt;</code>.
+     */
+    @Unused
+    String referencedClassName();
+
+    /**
+     * Get the class doc referenced by the class name part of @see.
+     * Return null if the class cannot be found.
+     * For example, for:
+     * <p>
+     *   &nbsp;&nbsp;<code>@see String#valueOf(java.lang.Object)</code>
+     * </p>
+     * return the <code>ClassDoc</code> for <code>java.lang.String</code>.
+     */
+    @Unused
+    ClassDoc referencedClass();
+
+    /**
+     * Get the field, constructor or method substring of the <code>@see</code>
+     * reference. Return null if the reference is to any other
+     * element or to any non-element.
+     * References to member classes (nested classes) return null.
+     * For example, for:
+     * <p>
+     *   &nbsp;&nbsp;<code>@see String#startsWith(String)</code>
+     * </p>
+     * return "startsWith(String)".
+     */
+    @Unused
+    String referencedMemberName();
+
+    /**
+     * Get the member doc for the field, constructor or method
+     * referenced by <code>@see</code>. Return null if the member cannot
+     * be found or if the reference is to any other element or to any
+     * non-element.
+     * References to member classes (nested classes) return null.
+     * For example, for:
+     * <p>
+     *   &nbsp;&nbsp;<code>@see String#startsWith(java.lang.String)</code>
+     * </p>
+     * return the <code>MethodDoc</code> for <code>startsWith</code>.
+     */
+    @Unused
+    MemberDoc referencedMember();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/SerialFieldTag.java b/doclet_adapter/src/main/java/com/sun/javadoc/SerialFieldTag.java
new file mode 100644
index 0000000..54ac120
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/SerialFieldTag.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Unused;
+
+/**
+ * Documents a Serializable field defined by an ObjectStreamField.
+ * <pre>
+ * The class parses and stores the three serialField tag parameters:
+ *
+ * - field name
+ * - field type name
+ *      (fully-qualified or visible from the current import context)
+ * - description of the valid values for the field
+
+ * </pre>
+ * This tag is only allowed in the javadoc for the special member
+ * serialPersistentFields.
+ *
+ * @author Joe Fialli
+ *
+ * @see java.io.ObjectStreamField
+ */
+public interface SerialFieldTag extends Tag, Comparable<Object> {
+
+    /**
+     * Return the serializable field name.
+     */
+    @Unused
+    String fieldName();
+
+    /**
+     * Return the field type string.
+     */
+    @Unused
+    String fieldType();
+
+    /**
+     * Return the ClassDoc for field type.
+     *
+     * @return null if no ClassDoc for field type is visible from
+     *         containingClass context.
+     */
+    @Unused
+    ClassDoc fieldTypeDoc();
+
+    /**
+     * Return the field comment. If there is no serialField comment, return
+     * javadoc comment of corresponding FieldDoc.
+     */
+    @Unused
+    String description();
+
+    /**
+     * Compares this Object with the specified Object for order.  Returns a
+     * negative integer, zero, or a positive integer as this Object is less
+     * than, equal to, or greater than the given Object.
+     * <p>
+     * Included to make SerialFieldTag items java.lang.Comparable.
+     *
+     * @param   obj the <code>Object</code> to be compared.
+     * @return  a negative integer, zero, or a positive integer as this Object
+     *          is less than, equal to, or greater than the given Object.
+     * @exception ClassCastException the specified Object's type prevents it
+     *            from being compared to this Object.
+     * @since 1.2
+     */
+    int compareTo(Object obj);
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/SourcePosition.java b/doclet_adapter/src/main/java/com/sun/javadoc/SourcePosition.java
new file mode 100644
index 0000000..27f1acd
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/SourcePosition.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2001, 2002, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import java.io.File;
+
+/**
+ * This interface describes a source position: filename, line number,
+ * and column number.
+ *
+ * @since 1.4
+ * @author Neal M Gafter
+ */
+public interface SourcePosition {
+    /** The source file. Returns null if no file information is
+     *  available. */
+    @Used
+    File file();
+
+    /** The line in the source file. The first line is numbered 1;
+     *  0 means no line number information is available. */
+    @Used
+    int line();
+
+    /** The column in the source file. The first column is
+     *  numbered 1; 0 means no column information is available.
+     *  Columns count characters in the input stream; a tab
+     *  advances the column number to the next 8-column tab stop.
+     */
+    @Used
+    int column();
+
+    /** Convert the source position to the form "Filename:line". */
+    @Unused
+    String toString();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/Tag.java b/doclet_adapter/src/main/java/com/sun/javadoc/Tag.java
new file mode 100644
index 0000000..2a1d4d8
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/Tag.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+import java.text.BreakIterator;
+import java.util.Locale;
+
+/**
+ * Represents a simple documentation tag, such as @since, @author, @version.
+ * Given a tag (e.g. "@since 1.2"), holds tag name (e.g. "@since")
+ * and tag text (e.g. "1.2").  Tags with structure or which require
+ * special processing are handled by subclasses such as ParamTag
+ * (for @param), SeeTag (for @see and {&#064;link}), and ThrowsTag
+ * (for @throws).
+ *
+ * @author Robert Field
+ * @author Atul M Dambalkar
+ * @see SeeTag
+ * @see ParamTag
+ * @see ThrowsTag
+ * @see SerialFieldTag
+ * @see Doc#tags()
+ *
+ */
+public interface Tag {
+
+    /**
+     * Return the name of this tag.  The name is the string
+     * starting with "@" that is used in a doc comment, such as
+     * <code>@return</code>.  For inline tags, such as
+     * <code>{&#064;link}</code>, the curly brackets
+     * are not part of the name, so in this example the name
+     * would be simply <code>@link</code>.
+     *
+     * @return the name of this tag
+     */
+    @Used
+    String name();
+
+    /**
+     * Return the containing {@link Doc} of this Tag element.
+     *
+     * @return the containing {@link Doc} of this Tag element
+     */
+    @Unused
+    Doc holder();
+
+    /**
+     * Return the kind of this tag.
+     * For most tags,
+     * <code>kind()&nbsp;==&nbsp;name()</code>;
+     * the following table lists those cases where there is more
+     * than one tag of a given kind:
+     *
+     * <table border="1" cellpadding="4" cellspacing="0" summary="related tags">
+     * <tr><th>{@code kind()  }</th>  <th>{@code name()      }</th></tr>
+     * <tr><td>{@code @throws }</td>  <td>{@code @throws     }</td></tr>
+     * <tr><td>{@code @throws }</td>  <td>{@code @exception  }</td></tr>
+     * <tr><td>{@code @see    }</td>  <td>{@code @see        }</td></tr>
+     * <tr><td>{@code @see    }</td>  <td>{@code @link       }</td></tr>
+     * <tr><td>{@code @see    }</td>  <td>{@code @linkplain  }</td></tr>
+     * <tr><td>{@code @serial }</td>  <td>{@code @serial     }</td></tr>
+     * <tr><td>{@code @serial }</td>  <td>{@code @serialData }</td></tr>
+     * </table>
+     *
+     * @return the kind of this tag.
+     */
+    @Used
+    String kind();
+
+    /**
+     * Return the text of this tag, that is, the portion beyond tag name.
+     *
+     * @return the text of this tag
+     */
+    @Used
+    String text();
+
+    /**
+     * Convert this object to a string.
+     */
+    @Unused
+    String toString();
+
+    /**
+     * For a documentation comment with embedded <code>{&#064;link}</code>
+     * tags, return an array of <code>Tag</code> objects.  The entire
+     * doc comment is broken down into strings separated by
+     * <code>{&#064;link}</code> tags, where each successive element
+     * of the array represents either a string or
+     * <code>{&#064;link}</code> tag, in order, from start to end.
+     * Each string is represented by a <code>Tag</code> object of
+     * name "Text", where {@link #text()} returns the string.  Each
+     * <code>{&#064;link}</code> tag is represented by a
+     * {@link SeeTag} of name "@link" and kind "@see".
+     * For example, given the following comment
+     * tag:
+     * <p>
+     *  <code>This is a {&#064;link Doc commentlabel} example.</code>
+     * <p>
+     * return an array of Tag objects:
+     * <ul>
+     *    <li> tags[0] is a {@link Tag} with name "Text" and text consisting
+     *         of "This is a "
+     *    <li> tags[1] is a {@link SeeTag} with name "@link", referenced
+     *         class <code>Doc</code> and label "commentlabel"
+     *    <li> tags[2] is a {@link Tag} with name "Text" and text consisting
+     *         of " example."
+     * </ul>
+     *
+     * @return Tag[] array of tags
+     * @see ParamTag
+     * @see ThrowsTag
+     */
+    @Unused
+    Tag[] inlineTags();
+
+    /**
+     * Return the first sentence of the comment as an array of tags.
+     * Includes inline tags
+     * (i.e. {&#64;link <i>reference</i>} tags)  but not
+     * block tags.
+     * Each section of plain text is represented as a {@link Tag}
+     * of kind "Text".
+     * Inline tags are represented as a {@link SeeTag} of kind "@link".
+     * If the locale is English language, the first sentence is
+     * determined by the rules described in the Java Language
+     * Specification (first version): &quot;This sentence ends
+     * at the first period that is followed by a blank, tab, or
+     * line terminator or at the first tagline.&quot;, in
+     * addition a line will be terminated by paragraph and
+     * section terminating HTML tags: &lt;p&gt;  &lt;/p&gt;  &lt;h1&gt;
+     * &lt;h2&gt;  &lt;h3&gt; &lt;h4&gt;  &lt;h5&gt;  &lt;h6&gt;
+     * &lt;hr&gt;  &lt;pre&gt;  or &lt;/pre&gt;.
+     * If the locale is not English, the sentence end will be
+     * determined by
+     * {@link BreakIterator#getSentenceInstance(Locale)}.
+     *
+     * @return an array of {@link Tag} objects representing the
+     *         first sentence of the comment
+     */
+    @Unused
+    Tag[] firstSentenceTags();
+
+    /**
+     * Return the source position of this tag.
+     * @return the source position of this tag.
+     */
+    @Used
+    SourcePosition position();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/ThrowsTag.java b/doclet_adapter/src/main/java/com/sun/javadoc/ThrowsTag.java
new file mode 100644
index 0000000..b24af85
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/ThrowsTag.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents a @throws or @exception documentation tag.
+ * Parses and holds the exception name and exception comment.
+ * Note: @exception is a backwards compatible synonymy for @throws.
+ *
+ * @author Robert Field
+ * @author Atul M Dambalkar
+ * @see ExecutableMemberDoc#throwsTags()
+ *
+ */
+public interface ThrowsTag extends Tag {
+
+    /**
+     * Return the name of the exception
+     * associated with this <code>ThrowsTag</code>.
+     *
+     * @return name of the exception.
+     */
+    @Unused
+    String exceptionName();
+
+    /**
+     * Return the exception comment
+     * associated with this <code>ThrowsTag</code>.
+     *
+     * @return exception comment.
+     */
+    @Used
+    String exceptionComment();
+
+    /**
+     * Return a <code>ClassDoc</code> that represents the exception.
+     * If the type of the exception is a type variable, return the
+     * <code>ClassDoc</code> of its erasure.
+     *
+     * <p> <i>This method cannot accommodate certain generic type
+     * constructs.  The <code>exceptionType</code> method
+     * should be used instead.</i>
+     *
+     * @return <code>ClassDoc</code> that represents the exception.
+     * @see #exceptionType
+     */
+    @Used
+    ClassDoc exception();
+
+    /**
+     * Return the type of the exception
+     * associated with this <code>ThrowsTag</code>.
+     * This may be a <code>ClassDoc</code> or a <code>TypeVariable</code>.
+     *
+     * @return the type of the exception.
+     * @since 1.5
+     */
+    @Unused
+    Type exceptionType();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/Type.java b/doclet_adapter/src/main/java/com/sun/javadoc/Type.java
new file mode 100644
index 0000000..207dfc4
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/Type.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents a type.  A type can be a class or interface, an
+ * invocation (like {@code List<String>}) of a generic class or interface,
+ * a type variable, a wildcard type ("<code>?</code>"),
+ * or a primitive data type (like <code>char</code>).
+ *
+ * @since 1.2
+ * @author Kaiyang Liu (original)
+ * @author Robert Field (rewrite)
+ * @author Scott Seligman (generics)
+ */
+public interface Type {
+
+    /**
+     * Return unqualified name of type excluding any dimension information.
+     * <p>
+     * For example, a two dimensional array of String returns
+     * "<code>String</code>".
+     */
+    @Unused
+    String typeName();
+
+    /**
+     * Return qualified name of type excluding any dimension information.
+     *<p>
+     * For example, a two dimensional array of String
+     * returns "<code>java.lang.String</code>".
+     */
+    @Used
+    String qualifiedTypeName();
+
+    /**
+     * Return the simple name of this type excluding any dimension information.
+     * This is the unqualified name of the type, except that for nested types
+     * only the identifier of the innermost type is included.
+     * <p>
+     * For example, the class {@code Outer.Inner} returns
+     * "<code>Inner</code>".
+     *
+     * @since 1.5
+     */
+    @Used
+    String simpleTypeName();
+
+    /**
+     * Return the type's dimension information, as a string.
+     * <p>
+     * For example, a two dimensional array of String returns
+     * "<code>[][]</code>".
+     */
+    @Used
+    String dimension();
+
+    /**
+     * Return a string representation of the type.
+     * This includes any dimension information and type arguments.
+     * <p>
+     * For example, a two dimensional array of String may return
+     * "<code>java.lang.String[][]</code>",
+     * and the parameterized type {@code List<Integer>} may return
+     * "{@code java.util.List<java.lang.Integer>}".
+     *
+     * @return a string representation of the type.
+     */
+    @Used
+    String toString();
+
+    /**
+     * Return true if this type represents a primitive type.
+     *
+     * @return true if this type represents a primitive type.
+     * @since 1.5
+     */
+    @Used
+    boolean isPrimitive();
+
+    /**
+     * Return this type as a <code>ClassDoc</code> if it represents a class
+     * or interface.  Array dimensions are ignored.
+     * If this type is a <code>ParameterizedType</code>,
+     * <code>TypeVariable</code>, or <code>WildcardType</code>, return
+     * the <code>ClassDoc</code> of the type's erasure.  If this is an
+     * <code>AnnotationTypeDoc</code>, return this as a <code>ClassDoc</code>
+     * (but see {@link #asAnnotationTypeDoc()}).
+     * If this is a primitive type, return null.
+     *
+     * @return the <code>ClassDoc</code> of this type,
+     *         or null if it is a primitive type.
+     */
+    @Used
+    ClassDoc asClassDoc();
+
+    /**
+     * Return this type as a <code>ParameterizedType</code> if it represents
+     * an invocation of a generic class or interface.  Array dimensions
+     * are ignored.
+     *
+     * @return a <code>ParameterizedType</code> if the type is an
+     *         invocation of a generic type, or null if it is not.
+     * @since 1.5
+     */
+    @Used
+    ParameterizedType asParameterizedType();
+
+    /**
+     * Return this type as a <code>TypeVariable</code> if it represents
+     * a type variable.  Array dimensions are ignored.
+     *
+     * @return a <code>TypeVariable</code> if the type is a type variable,
+     *         or null if it is not.
+     * @since 1.5
+     */
+    @Used
+    TypeVariable asTypeVariable();
+
+    /**
+     * Return this type as a <code>WildcardType</code> if it represents
+     * a wildcard type.
+     *
+     * @return a <code>WildcardType</code> if the type is a wildcard type,
+     *         or null if it is not.
+     * @since 1.5
+     */
+    @Used
+    WildcardType asWildcardType();
+
+    /**
+     * Returns this type as a <code>AnnotatedType</code> if it represents
+     * an annotated type.
+     *
+     * @return a <code>AnnotatedType</code> if the type if an annotated type,
+     *         or null if it is not
+     * @since 1.8
+     */
+    @Used
+    AnnotatedType asAnnotatedType();
+
+    /**
+     * Return this type as an <code>AnnotationTypeDoc</code> if it represents
+     * an annotation type.  Array dimensions are ignored.
+     *
+     * @return an <code>AnnotationTypeDoc</code> if the type is an annotation
+     *         type, or null if it is not.
+     * @since 1.5
+     */
+    @Unused
+    AnnotationTypeDoc asAnnotationTypeDoc();
+
+    /**
+     * If this type is an array type, return the element type of the
+     * array. Otherwise, return null.
+     *
+     * @return a <code>Type</code> representing the element type or null.
+     * @since 1.8
+     */
+    @Unused
+    Type getElementType();
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/TypeVariable.java b/doclet_adapter/src/main/java/com/sun/javadoc/TypeVariable.java
new file mode 100644
index 0000000..2d8db2e
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/TypeVariable.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+
+import com.google.doclava.annotation.Unused;
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents a type variable.
+ * For example, the generic interface {@code List<E>} has a single
+ * type variable {@code E}.
+ * A type variable may have explicit bounds, as in
+ * {@code C<R extends Remote>}.
+ *
+ * @author Scott Seligman
+ * @since 1.5
+ */
+public interface TypeVariable extends Type {
+
+    /**
+     * Return the bounds of this type variable.
+     * These are the types given by the <i>extends</i> clause.
+     * Return an empty array if there are no explicit bounds.
+     *
+     * @return the bounds of this type variable.
+     */
+    @Used
+    Type[] bounds();
+
+    /**
+     * Return the class, interface, method, or constructor within
+     * which this type variable is declared.
+     *
+     * @return the class, interface, method, or constructor within
+     *         which this type variable is declared.
+     */
+    @Unused
+    ProgramElementDoc owner();
+
+    /**
+     * Get the annotations of this program element.
+     * Return an empty array if there are none.
+     */
+    @Unused
+    AnnotationDesc[] annotations();
+
+}
diff --git a/doclet_adapter/src/main/java/com/sun/javadoc/WildcardType.java b/doclet_adapter/src/main/java/com/sun/javadoc/WildcardType.java
new file mode 100644
index 0000000..0178463
--- /dev/null
+++ b/doclet_adapter/src/main/java/com/sun/javadoc/WildcardType.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javadoc;
+
+
+import com.google.doclava.annotation.Used;
+
+/**
+ * Represents a wildcard type argument.
+ * Examples include:    <pre>
+ * {@code <?>}
+ * {@code <? extends E>}
+ * {@code <? super T>}
+ * </pre>
+ * A wildcard type can have explicit <i>extends</i> bounds
+ * or explicit <i>super</i> bounds or neither, but not both.
+ *
+ * @author Scott Seligman
+ * @since 1.5
+ */
+public interface WildcardType extends Type {
+
+    /**
+     * Return the upper bounds of this wildcard type argument
+     * as given by the <i>extends</i> clause.
+     * Return an empty array if no such bounds are explicitly given.
+     *
+     * @return the extends bounds of this wildcard type argument
+     */
+    @Used
+    Type[] extendsBounds();
+
+    /**
+     * Return the lower bounds of this wildcard type argument
+     * as given by the <i>super</i> clause.
+     * Return an empty array if no such bounds are explicitly given.
+     *
+     * @return the super bounds of this wildcard type argument
+     */
+    @Used
+    Type[] superBounds();
+}
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/AnnotatedTypeImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/AnnotatedTypeImplTest.java
new file mode 100644
index 0000000..9e03da8
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/AnnotatedTypeImplTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.assertEquals;
+
+import com.sun.javadoc.Type;
+import javax.lang.model.type.DeclaredType;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class AnnotatedTypeImplTest extends BaseTest {
+
+    private AnnotatedTypeImpl annotatedClass;
+
+    @Override
+    public void setUp() {
+        super.setUp();
+
+        annotatedClass = AnnotatedTypeImpl.create((DeclaredType) CLASS.annotatedClass.asType(),
+                context);
+    }
+
+    @Ignore("Not used")
+    @Test
+    public void annotations() {
+    }
+
+    @Test
+    public void underlyingType() {
+        Type underlyingType = annotatedClass.underlyingType();
+        assertEquals("AnnotatedClass", underlyingType.typeName());
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/AnnotationMethodDocImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/AnnotationMethodDocImplTest.java
new file mode 100644
index 0000000..5b66f5f
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/AnnotationMethodDocImplTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class AnnotationMethodDocImplTest extends BaseTest {
+
+    private AnnotationMethodDocImpl withDefault;
+    private AnnotationMethodDocImpl withoutDefault;
+
+    @Override
+    @Before
+    public void setUp() {
+        super.setUp();
+        withoutDefault = AnnotationMethodDocImpl.create(ANNOTATION_METHOD.annotationMethod, context);
+        withDefault =
+                AnnotationMethodDocImpl.create(ANNOTATION_METHOD.annotationMethodWithDefault, context);
+    }
+
+    @Test
+    public void defaultValue() {
+        assertNull(withoutDefault.defaultValue());
+
+        assertNotNull(withDefault.defaultValue());
+    }
+
+    @Test
+    public void isAnnotationTypeElement() {
+        assertTrue(withoutDefault.isAnnotationTypeElement());
+        assertTrue(withDefault.isAnnotationTypeElement());
+    }
+
+    @Test
+    public void isMethod() {
+        assertFalse(withoutDefault.isMethod());
+        assertFalse(withDefault.isMethod());
+    }
+
+    @Test
+    public void isAbstract() {
+        assertFalse(withoutDefault.isAbstract());
+        assertFalse(withDefault.isAbstract());
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/AnnotationTypeDocImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/AnnotationTypeDocImplTest.java
new file mode 100644
index 0000000..f1cdc86
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/AnnotationTypeDocImplTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class AnnotationTypeDocImplTest extends BaseTest {
+
+    private AnnotationTypeDocImpl empty;
+
+    @Override
+    @Before
+    public void setUp() {
+        super.setUp();
+        empty = AnnotationTypeDocImpl.create(CLASS.publicAnnotation, context);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void create() {
+        AnnotationTypeDocImpl.create(CLASS.publicClass, context);
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void elements() {
+    }
+
+    @Test
+    public void isAnnotationType() {
+        assertTrue(empty.isAnnotationType());
+    }
+
+    @Test
+    public void isInterface() {
+        assertFalse(empty.isInterface());
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/AnnotationValueImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/AnnotationValueImplTest.java
new file mode 100644
index 0000000..357f8eb
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/AnnotationValueImplTest.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.doclava.javadoc.BaseTest.ANNOTATION_METHOD.WITH_DEFAULT;
+import com.sun.javadoc.Type;
+import javax.lang.model.element.AnnotationValue;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class AnnotationValueImplTest extends BaseTest {
+
+    private static final AnnotationValue withDefault = ANNOTATION_METHOD.annotationMethodWithDefault.getDefaultValue();
+
+    @Before
+    public void setUp() {
+        super.setUp();
+
+    }
+
+    @Test
+    public void create() {
+        assertNull(AnnotationValueImpl.create(null, context));
+
+        var av = AnnotationValueImpl.create(withDefault, context);
+        assertNotNull(av);
+    }
+
+    @Test
+    public void value_ofNull() {
+        assertNull(AnnotationValueImpl.create(null, context));
+    }
+
+    @Test
+    public void value_ofBool() {
+        AnnotationValueImpl b = AnnotationValueImpl.create(
+                WITH_DEFAULT.returningBool.getDefaultValue(), context);
+        assertNotNull(b);
+        Object value = b.value();
+        assertNotNull(value);
+
+        assertTrue(value instanceof Boolean);
+        assertEquals(true, value);
+    }
+
+    @Test
+    public void value_ofByte() {
+        AnnotationValueImpl b = AnnotationValueImpl.create(
+                WITH_DEFAULT.returningByte.getDefaultValue(), context);
+        assertNotNull(b);
+        Object value = b.value();
+
+        assertTrue(value instanceof Byte);
+        assertEquals((byte) 1, value);
+    }
+
+    @Test
+    public void value_ofChar() {
+        AnnotationValueImpl b = AnnotationValueImpl.create(
+                WITH_DEFAULT.returningChar.getDefaultValue(), context);
+        assertNotNull(b);
+        Object value = b.value();
+
+        assertTrue(value instanceof Character);
+        assertEquals('a', value);
+    }
+
+    @Test
+    public void value_ofDouble() {
+        AnnotationValueImpl b = AnnotationValueImpl.create(
+                WITH_DEFAULT.returningDouble.getDefaultValue(), context);
+        assertNotNull(b);
+        Object value = b.value();
+
+        assertTrue(value instanceof Double);
+        assertEquals(3.1d, (double) value, 0.0000001d);
+    }
+
+    @Test
+    public void value_ofFloat() {
+        AnnotationValueImpl b = AnnotationValueImpl.create(
+                WITH_DEFAULT.returningFloat.getDefaultValue(), context);
+        assertNotNull(b);
+        Object value = b.value();
+
+        assertTrue(value instanceof Float);
+        assertEquals(4.1f, (float) value, 0.0000001f);
+    }
+
+    @Test
+    public void value_ofInteger() {
+        AnnotationValueImpl b = AnnotationValueImpl.create(
+                ANNOTATION_METHOD.WITH_DEFAULT.returningInteger.getDefaultValue(), context);
+        assertNotNull(b);
+        Object value = b.value();
+
+        assertTrue(value instanceof Integer);
+        assertEquals(5, value);
+    }
+
+    @Test
+    public void value_ofLong() {
+        AnnotationValueImpl b = AnnotationValueImpl.create(
+                WITH_DEFAULT.returningLond.getDefaultValue(), context);
+        assertNotNull(b);
+        Object value = b.value();
+
+        assertTrue(value instanceof Long);
+        assertEquals(6L, value);
+    }
+
+    @Test
+    public void value_ofShort() {
+        AnnotationValueImpl b = AnnotationValueImpl.create(
+                WITH_DEFAULT.returningShort.getDefaultValue(), context);
+        assertNotNull(b);
+        Object value = b.value();
+
+        assertTrue(value instanceof Short);
+        assertEquals((short) 7, value);
+    }
+
+    @Test
+    public void value_ofString() {
+        AnnotationValueImpl b = AnnotationValueImpl.create(
+                WITH_DEFAULT.returningString.getDefaultValue(), context);
+        assertNotNull(b);
+        Object value = b.value();
+
+        assertTrue(value instanceof String);
+        assertEquals("qwe", value);
+    }
+
+    @Test
+    public void value_ofClass() {
+        AnnotationValueImpl b = AnnotationValueImpl.create(
+                WITH_DEFAULT.returningClass.getDefaultValue(), context);
+        assertNotNull(b);
+        Object value = b.value();
+
+        assertTrue(value instanceof Type);
+        assertTrue(value instanceof ClassDocImpl);
+        assertEquals("com.example.classes.PublicClass", ((ClassDocImpl) value).qualifiedName());
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void value_ofEnum() {
+        AnnotationValueImpl b = AnnotationValueImpl.create(
+                WITH_DEFAULT.returningEnum.getDefaultValue(), context);
+        assertNotNull(b);
+        Object value = b.value();
+
+        assertTrue(value instanceof FieldDocImpl);
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void value_ofAnnotation() {
+        AnnotationValueImpl b = AnnotationValueImpl.create(
+                WITH_DEFAULT.returningAnnotation.getDefaultValue(), context);
+        assertNotNull(b);
+        Object value = b.value();
+    }
+
+    @Test
+    public void value_ofArrayOfString() {
+        AnnotationValueImpl b = AnnotationValueImpl.create(
+                WITH_DEFAULT.returningArrayOfString.getDefaultValue(), context);
+        assertNotNull(b);
+        Object value = b.value();
+
+        assertTrue(value instanceof AnnotationValueImpl[]);
+        var arr = (AnnotationValueImpl[]) value;
+        assertEquals(3, arr.length);
+
+        var expected = new String[]{"abc", "def", "ghi"};
+        for (int i = 0; i < arr.length; i++) {
+            var unwrapped = arr[i].value();
+            assertTrue(unwrapped instanceof String);
+            assertEquals(expected[i], unwrapped);
+        }
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/ArrayTypeImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/ArrayTypeImplTest.java
new file mode 100644
index 0000000..0bdcda6
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/ArrayTypeImplTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.sun.javadoc.AnnotationTypeDoc;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.ParameterizedType;
+import com.sun.javadoc.TypeVariable;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class ArrayTypeImplTest extends BaseTest {
+
+    // All these are declared in com.example.fields.Arrays class.
+    private ArrayTypeImpl int_1;           // primitive type     : int[]
+    private ArrayTypeImpl string_2;        // class              : String[][]
+    private ArrayTypeImpl typeVar_3;       // type variable      : T[][][]
+    private ArrayTypeImpl listOfStrings_4; // parameterized type : List<String>[][][][]
+    private ArrayTypeImpl annotation_5;    // annotation         : @Override[][][][][]
+
+    @Before
+    public void setUp() {
+        super.setUp();
+
+        int_1 = ArrayTypeImpl.create(ARRAY.int_1, context);
+        string_2 = ArrayTypeImpl.create(ARRAY.string_2, context);
+        typeVar_3 = ArrayTypeImpl.create(ARRAY.T_3, context);
+        listOfStrings_4 = ArrayTypeImpl.create(ARRAY.ListOfStrings_4, context);
+        annotation_5 = ArrayTypeImpl.create(ARRAY.override_5, context);
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void getElementType() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void typeName() {
+    }
+
+    @Test
+    public void qualifiedTypeName() {
+        assertEquals("int", int_1.qualifiedTypeName());
+        assertEquals("java.lang.String", string_2.qualifiedTypeName());
+        assertEquals("T", typeVar_3.qualifiedTypeName());
+        assertEquals("java.util.List<java.lang.String>", listOfStrings_4.qualifiedTypeName());
+        assertEquals("java.lang.Override", annotation_5.qualifiedTypeName());
+    }
+
+    @Test
+    public void simpleTypeName() {
+        assertEquals("int", int_1.simpleTypeName());
+        assertEquals("String", string_2.simpleTypeName());
+        assertEquals("T", typeVar_3.simpleTypeName());
+        assertEquals("List", listOfStrings_4.simpleTypeName());
+        assertEquals("Override", annotation_5.simpleTypeName());
+    }
+
+    @Test
+    public void dimension() {
+        assertEquals("[]", int_1.dimension());
+        assertEquals("[][]", string_2.dimension());
+        assertEquals("[][][]", typeVar_3.dimension());
+        assertEquals("[][][][]", listOfStrings_4.dimension());
+        assertEquals("[][][][][]", annotation_5.dimension());
+    }
+
+    @Test
+    public void asClassDoc() {
+        assertNull(int_1.asClassDoc());
+        assertNull(typeVar_3.asClassDoc());
+        assertNull(listOfStrings_4.asClassDoc());
+
+        ClassDoc string = string_2.asClassDoc();
+        assertTrue(string.isClass());
+        assertEquals("java.lang.String", string.qualifiedTypeName());
+
+        ClassDoc annotation = annotation_5.asClassDoc();
+        assertTrue(annotation.isAnnotationType());
+        assertEquals("java.lang.Override", annotation.qualifiedTypeName());
+    }
+
+    @Test
+    public void asTypeVariable() {
+        assertNull(int_1.asTypeVariable());
+        assertNull(string_2.asTypeVariable());
+        assertNull(listOfStrings_4.asTypeVariable());
+        assertNull(annotation_5.asTypeVariable());
+
+        TypeVariable tv = typeVar_3.asTypeVariable();
+        assertEquals("T", tv.simpleTypeName());
+    }
+
+    @Test
+    public void asParameterizedType() {
+        assertNull(int_1.asParameterizedType());
+        assertNull(string_2.asParameterizedType());
+        assertNull(typeVar_3.asParameterizedType());
+        assertNull(annotation_5.asParameterizedType());
+
+        ParameterizedType pt = listOfStrings_4.asParameterizedType();
+        assertEquals("java.util.List<java.lang.String>", pt.qualifiedTypeName());
+    }
+
+    @Test
+    public void asAnnotationTypeDoc() {
+        assertNull(int_1.asAnnotationTypeDoc());
+        assertNull(string_2.asAnnotationTypeDoc());
+        assertNull(typeVar_3.asAnnotationTypeDoc());
+        assertNull(listOfStrings_4.asAnnotationTypeDoc());
+
+        AnnotationTypeDoc atd = annotation_5.asAnnotationTypeDoc();
+        assertTrue(atd.isAnnotationType());
+        assertEquals("java.lang.Override", atd.qualifiedTypeName());
+    }
+
+    @Test
+    public void isPrimitive() {
+        assertFalse(string_2.isPrimitive());
+        assertFalse(typeVar_3.isPrimitive());
+        assertFalse(listOfStrings_4.isPrimitive());
+        assertFalse(annotation_5.isPrimitive());
+
+        assertTrue(int_1.isPrimitive());
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/BaseTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/BaseTest.java
new file mode 100644
index 0000000..96ecfb9
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/BaseTest.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import jdk.javadoc.doclet.DocletEnvironment;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public abstract class BaseTest {
+
+    protected static RootDocImpl rootDoc;
+    protected static DocletEnvironment docletEnv;
+    protected Context context;
+
+    /**
+     * @implNote While marked with {@link BeforeClass}, the actual initialization happens only once
+     * across multiple runs by test subclasses, which results are stored in a singleton manner.
+     */
+    @BeforeClass
+    public static void beforeClass() {
+        if (docletEnv != null && rootDoc != null) {
+            return;
+        }
+
+        var doclet = new EmptyDoclet("src/test/resources");
+        docletEnv = doclet.getEnvironment();
+
+        rootDoc = new RootDocImpl(docletEnv);
+    }
+
+    @Before
+    public void setUp() {
+        context = new Context(docletEnv);
+    }
+
+    // TypeElements (ANNOTATION_TYPE, CLASS, ENUM, INTERFACE, or RECORD).
+    static class CLASS {
+
+        static final TypeElement publicAbstractClass = initTypeElement(
+                "com.example.classes.AbstractEmptyClass");
+        static final TypeElement publicAbstractInterface = initTypeElement(
+                "com.example.classes.AbstractEmptyInterface");
+
+        static final TypeElement publicAnnotation = initTypeElement(
+                "com.example.classes.PublicAnnotation");
+        static final TypeElement publicClass = initTypeElement("com.example.classes.PublicClass");
+        static final TypeElement publicEnum = initTypeElement("com.example.classes.PublicEnum");
+        static final TypeElement publicInterface = initTypeElement(
+                "com.example.classes.PublicInterface");
+
+        static final TypeElement simpleEnum = initTypeElement("com.example.classes.SimpleEnum");
+
+        static final TypeElement publicClassWithNests = initTypeElement(
+                "com.example.classes.PublicClassWithNests");
+        static final TypeElement publicClassWithNests$Nest1 = initTypeElement(
+                "com.example.classes.PublicClassWithNests.Nest1");
+        static final TypeElement publicClassWithNests$Nest1$Nest2 = initTypeElement(
+                "com.example.classes.PublicClassWithNests.Nest1.Nest2");
+        static final TypeElement publicClassWithNests$Nest1$Nest2$Nest3 = initTypeElement(
+                "com.example.classes.PublicClassWithNests.Nest1.Nest2.Nest3");
+        static final TypeElement innerClasses = initTypeElement(
+                "com.example.classes.InnerClasses");
+
+        static final TypeElement parametrizedAnnotation = initTypeElement(
+                "com.example.classes.ParametrizedAnnotation");
+
+        static final TypeElement tags = initTypeElement("com.example.classes.Tags");
+        static final TypeElement tags$See = initTypeElement("com.example.classes.Tags.See");
+        static final TypeElement tags$Throws = initTypeElement("com.example.classes.Tags.Throws");
+        static final TypeElement tags$Various = initTypeElement("com.example.classes.Tags.Various");
+
+        static final TypeElement constructors = initTypeElement(
+                "com.example.constructors.Constructors");
+
+        static final TypeElement packagePrivateClass = initTypeElement(
+                "com.example.classes.PackagePrivateClass");
+
+        static final TypeElement implementsSerializable = initTypeElement(
+                "com.example.classes.ImplementsSerializable");
+        static final TypeElement implementsExternalizable = initTypeElement(
+                "com.example.classes.ImplementsExternalizable");
+
+        static final TypeElement annotatedClass = initTypeElement(
+                "com.example.classes.AnnotatedClass");
+
+        static final TypeElement javaUtilMap = initTypeElement("java.util.Map");
+
+        static final TypeElement fieldsAccessModifiers = initTypeElement(
+                "com.example.classes.FieldsAccessModifiers");
+        static final TypeElement methodsAccessModifiers = initTypeElement(
+                "com.example.classes.MethodsAccessModifiers");
+    }
+
+    static class GENERIC {
+
+        static final TypeElement box = initTypeElement("com.example.classes.Tags.Box");
+    }
+
+    static class ARRAY {
+
+        static final ArrayType int_1 = (ArrayType) initVariableElement(
+                "com.example.fields.Arrays", "arr_int_1").asType();
+        static final ArrayType string_2 = (ArrayType) initVariableElement(
+                "com.example.fields.Arrays", "arr_String_2").asType();
+        static final ArrayType T_3 = (ArrayType) initVariableElement(
+                "com.example.fields.Arrays", "arr_T_3").asType();
+        static final ArrayType ListOfStrings_4 = (ArrayType) initVariableElement(
+                "com.example.fields.Arrays", "arr_ListOfString_4").asType();
+        static final ArrayType override_5 = (ArrayType) initVariableElement(
+                "com.example.fields.Arrays", "arr_Override_5").asType();
+    }
+
+    static class INTERFACE {
+
+        static final TypeElement serializable = initTypeElement("java.io.Serializable");
+        static final TypeElement extendsSerializable = initTypeElement(
+                "com.example.classes.ExtendsSerializable");
+        static final TypeElement extendsExternalizable = initTypeElement(
+                "com.example.classes.ExtendsExternalizable");
+    }
+
+    static class INSTANCE {
+
+        static final TypeElement javaLangObject = initTypeElement("java.lang.Object");
+        static final TypeElement javaLangError = initTypeElement("java.lang.Error");
+        static final TypeElement javaLangException = initTypeElement("java.lang.Exception");
+        static final TypeElement javaLangString = initTypeElement("java.lang.String");
+        static final TypeElement javaLangThrowable = initTypeElement("java.lang.Throwable");
+    }
+
+    static class PACKAGE {
+
+        static PackageElement comExamplePackages = initPackageElement("com.example.packages");
+    }
+
+    static class ANNOTATION_METHOD {
+
+        /**
+         * <pre>
+         * public @interface AllDefaultAnnotation {
+         *     boolean bool() default true;
+         *     byte byt() default (byte)1;
+         *     char ch() default 'a';
+         *     double dbl() default 3.1d;
+         *     float flt() default 4.1f;
+         *     int integer() default 5;
+         *     long lng() default 6L;
+         *     short shrt() default (short)7;
+         *     String str() default "qwe";
+         *     Class<?> cls() default PublicClass.class;
+         *     SimpleEnum enm() default SimpleEnum.A;
+         *     Class<?> annotation() default Override.class;
+         *     String[] arrayOfStrings() default { "abc", "def", "ghi" };
+         * }
+         * </pre>
+         */
+        static class WITH_DEFAULT {
+
+            static final ExecutableElement returningBool = initExecutableElement(
+                    "com.example.classes.AllDefaultAnnotation", "bool()");
+            static final ExecutableElement returningByte = initExecutableElement(
+                    "com.example.classes.AllDefaultAnnotation", "byt()");
+            static final ExecutableElement returningChar = initExecutableElement(
+                    "com.example.classes.AllDefaultAnnotation", "ch()");
+            static final ExecutableElement returningDouble = initExecutableElement(
+                    "com.example.classes.AllDefaultAnnotation", "dbl()");
+            static final ExecutableElement returningFloat = initExecutableElement(
+                    "com.example.classes.AllDefaultAnnotation", "flt()");
+            static final ExecutableElement returningInteger = initExecutableElement(
+                    "com.example.classes.AllDefaultAnnotation", "integer()");
+            static final ExecutableElement returningLond = initExecutableElement(
+                    "com.example.classes.AllDefaultAnnotation", "lng()");
+            static final ExecutableElement returningShort = initExecutableElement(
+                    "com.example.classes.AllDefaultAnnotation", "shrt()");
+            static final ExecutableElement returningString = initExecutableElement(
+                    "com.example.classes.AllDefaultAnnotation", "str()");
+            static final ExecutableElement returningClass = initExecutableElement(
+                    "com.example.classes.AllDefaultAnnotation", "cls()");
+            static final ExecutableElement returningEnum = initExecutableElement(
+                    "com.example.classes.AllDefaultAnnotation", "enm()");
+            static final ExecutableElement returningAnnotation = initExecutableElement(
+                    "com.example.classes.AllDefaultAnnotation", "annotation()");
+            static final ExecutableElement returningArrayOfString = initExecutableElement(
+                    "com.example.classes.AllDefaultAnnotation", "arrayOfStrings()");
+        }
+
+        static final TypeElement allDefaultAnnotation = initTypeElement(
+                "com.example.classes.AllDefaultAnnotation");
+        static final ExecutableElement annotationMethod = initExecutableElement(
+                "com.example.classes.ParametrizedAnnotation", "primitiveI()");
+        static final ExecutableElement annotationMethodWithDefault = initExecutableElement(
+                "com.example.classes.ParametrizedAnnotation", "primitiveDefaultL()");
+    }
+
+    static class CONSTRUCTOR {
+
+        static final ExecutableElement empty = initExecutableElement(
+                "com.example.constructors.Constructors", "Constructors()");
+        static final ExecutableElement arg1_int = initExecutableElement(
+                "com.example.constructors.Constructors", "Constructors(int)");
+        static final ExecutableElement arg1_String = initExecutableElement(
+                "com.example.constructors.Constructors", "Constructors(java.lang.String)");
+        static final ExecutableElement arg2_int_String = initExecutableElement(
+                "com.example.constructors.Constructors", "Constructors(int,java.lang.String)");
+
+        static final ExecutableElement paramTag_arg2_T_int = initExecutableElement(
+                "com.example.classes.Tags.Box", "Box(T,int)");
+    }
+
+    static class METHOD {
+
+        static class OF_CLASS {
+
+            static final ExecutableElement public_void_arg0 = initExecutableElement(
+                    "com.example.methods.OfClass", "public_void_arg0()");
+            static final ExecutableElement private_int_arg0 = initExecutableElement(
+                    "com.example.methods.OfClass", "private_int_arg0()");
+            static final ExecutableElement packagePrivate_String_arg2_int_String = initExecutableElement(
+                    "com.example.methods.OfClass",
+                    "packagePrivate_String_arg2_int_String(int,java.lang.String)");
+            static final ExecutableElement public_abstract_void_arg0 = initExecutableElement(
+                    "com.example.methods.OfClass", "public_abstract_void_arg0()");
+            static final ExecutableElement override_public_String_toString0 = initExecutableElement(
+                    "com.example.methods.OfClass", "toString()");
+            static final ExecutableElement void_arg1_annotatedObject = initExecutableElement(
+                    "com.example.methods.OfClass",
+                    "void_arg1_annotatedObject(@com.example.classes.UniversalAnnotation java.lang.Object)");
+        }
+
+        static class OF_INTERFACE {
+
+            static final ExecutableElement public_void_arg0 = initExecutableElement(
+                    "com.example.methods.OfInterface", "public_void_arg0()");
+            static final ExecutableElement public_default_String_arg0 = initExecutableElement(
+                    "com.example.methods.OfInterface", "public_default_String_arg0()");
+        }
+
+        static class OVERRIDES {
+
+            static final ExecutableElement A_name = initExecutableElement(
+                    "com.example.methods.override.A", "name()");
+            static final ExecutableElement B_name = initExecutableElement(
+                    "com.example.methods.override.B", "name()");
+            static final ExecutableElement C_name = initExecutableElement(
+                    "com.example.methods.override.C", "name()");
+            static final ExecutableElement D_name = initExecutableElement(
+                    "com.example.methods.override.D", "name()");
+        }
+
+        static class PARAMETER {
+
+            static final VariableElement Object_annotatedWith_UniversalAnnotation = initMethodParam(
+                    "com.example.methods.OfClass",
+                    "void_arg1_annotatedObject(@com.example.classes.UniversalAnnotation java.lang.Object)",
+                    "obj");
+        }
+    }
+
+    static class FIELD {
+
+        static final VariableElement public_int = initVariableElement(
+                "com.example.fields.Fields", "public_int");
+        static final VariableElement public_transient_volatile_Object = initVariableElement(
+                "com.example.fields.Fields", "public_transient_volatile_Object");
+        static final VariableElement public_final_int = initVariableElement(
+                "com.example.fields.Fields", "public_final_int");
+        static final VariableElement public_final_String = initVariableElement(
+                "com.example.fields.Fields", "public_final_String");
+
+        static class ACCESS_MODIFIERS {
+
+            static final VariableElement public_int = initVariableElement(
+                    "com.example.fields.FieldsAccessModifiers", "public_int");
+            static final VariableElement private_int = initVariableElement(
+                    "com.example.fields.FieldsAccessModifiers", "private_int");
+            static final VariableElement protected_float = initVariableElement(
+                    "com.example.fields.FieldsAccessModifiers", "protected_float");
+            static final VariableElement packagePrivate_long = initVariableElement(
+                    "com.example.fields.FieldsAccessModifiers", "packagePrivate_long");
+        }
+    }
+
+    protected static TypeElement initTypeElement(String name) {
+        var e = docletEnv.getElementUtils().getTypeElement(name);
+        assertNotNull(e);
+        return e;
+    }
+
+    private static PackageElement initPackageElement(String name) {
+        var e = docletEnv.getElementUtils().getPackageElement(name);
+        assertNotNull(e);
+        return e;
+    }
+
+    private static VariableElement initMethodParam(String containingType, String methodSignature,
+            String parameterName) {
+        ExecutableElement method = initExecutableElement(containingType, methodSignature);
+        var params = method.getParameters()
+                .stream()
+                .filter(param -> param.getSimpleName().toString().equals(parameterName))
+                .toList();
+
+        assertEquals(1, params.size());
+        return params.get(0);
+    }
+
+    private static VariableElement initVariableElement(String containingType, String name) {
+        var t = initTypeElement(containingType);
+        var fields = t.getEnclosedElements()
+                .stream()
+                .filter(e -> e instanceof VariableElement)
+                .map(e -> (VariableElement) e)
+                .filter(ve -> name.equals(ve.getSimpleName().toString()))
+                .toList();
+
+        assertEquals(1, fields.size());
+        return fields.get(0);
+    }
+
+    /**
+     * Finds ExecutableElement in the environment by class type and element signature. Signature
+     * should be in the following format: {@code methodName(type1[,type2...])}, types are specified
+     * in a fully qualified form. For example:
+     *
+     * <ul>
+     *     <li>{@code Constructor()}</li>
+     *     <li>{@code Constructor(int)}</li>
+     *     <li>{@code update(java.lang.String,float)}</li>
+     * </ul>
+     *
+     * @param type fully qualified class name
+     * @param signature signature of executable element
+     * @return ExecutableElement
+     */
+    private static ExecutableElement initExecutableElement(String type, String signature) {
+        var t = initTypeElement(type);
+        var methods = t.getEnclosedElements()
+                .stream()
+                .filter(e -> e instanceof ExecutableElement)
+                .map(e -> (ExecutableElement) e)
+                .filter(exe -> signature.equals(exe.toString()))
+                .toList();
+
+        assertEquals(1, methods.size());
+        return methods.get(0);
+    }
+}
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/ClassDocImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/ClassDocImplTest.java
new file mode 100644
index 0000000..ef17e5c
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/ClassDocImplTest.java
@@ -0,0 +1,792 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.sun.javadoc.FieldDoc;
+import com.sun.javadoc.MethodDoc;
+import com.sun.javadoc.ProgramElementDoc;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class ClassDocImplTest extends BaseTest {
+
+    private ClassDocImpl abstractEmptyInterface;
+    private ClassDocImpl abstractEmptyClass;
+    private ClassDocImpl publicClass;
+    private ClassDocImpl publicEnum;
+    private ClassDocImpl publicAnnotation;
+    private ClassDocImpl publicInterface;
+    private ClassDocImpl simpleEnum;
+    private ClassDocImpl serializable;
+    private ClassDocImpl extendsSerializable;
+    private ClassDocImpl extendsExternalizable;
+    private ClassDocImpl implementsSerializable;
+    private ClassDocImpl implementsExternalizable;
+
+    private ClassDocImpl javaLangError;
+    private ClassDocImpl javaLangException;
+    private ClassDocImpl javaLangObject;
+    private ClassDocImpl javaLangThrowable;
+    private ClassDocImpl javaUtilMap;
+
+    private ClassDocImpl publicClassWithNests;
+    private ClassDocImpl publicClassWithNests$Nest1;
+    private ClassDocImpl publicClassWithNests$Nest1$Nest2;
+    private ClassDocImpl publicClassWithNests$Nest1$Nest2$Nest3;
+    private ClassDocImpl innerClasses;
+
+    private ClassDocImpl constructors;
+
+    private ClassDocImpl packagePrivateClass;
+
+    private ClassDocImpl fieldsAccessModifiers;
+    private ClassDocImpl methodsAccessModifiers;
+
+    @Before
+    public void setUp() {
+        super.setUp();
+        abstractEmptyClass = ClassDocImpl.create(CLASS.publicAbstractClass, context);
+        abstractEmptyInterface = ClassDocImpl.create(CLASS.publicAbstractInterface, context);
+
+        publicClass = ClassDocImpl.create(CLASS.publicClass, context);
+        publicClassWithNests = ClassDocImpl.create(CLASS.publicClassWithNests, context);
+        publicEnum = ClassDocImpl.create(CLASS.publicEnum, context);
+        simpleEnum = ClassDocImpl.create(CLASS.simpleEnum, context);
+        // note that it is created using AnnotationTypeDocImpl ctor.
+        publicAnnotation = AnnotationTypeDocImpl.create(CLASS.publicAnnotation, context);
+        publicInterface = ClassDocImpl.create(CLASS.publicInterface, context);
+        packagePrivateClass = ClassDocImpl.create(CLASS.packagePrivateClass, context);
+
+        javaLangError = ClassDocImpl.create(INSTANCE.javaLangError, context);
+        javaLangException = ClassDocImpl.create(INSTANCE.javaLangException, context);
+        javaLangObject = ClassDocImpl.create(INSTANCE.javaLangObject, context);
+        javaLangThrowable = ClassDocImpl.create(INSTANCE.javaLangThrowable, context);
+        javaUtilMap = ClassDocImpl.create(CLASS.javaUtilMap, context);
+
+        publicClassWithNests = ClassDocImpl.create(CLASS.publicClassWithNests, context);
+        publicClassWithNests$Nest1 = ClassDocImpl.create(CLASS.publicClassWithNests$Nest1, context);
+        publicClassWithNests$Nest1$Nest2 = ClassDocImpl.create(
+                CLASS.publicClassWithNests$Nest1$Nest2, context);
+        publicClassWithNests$Nest1$Nest2$Nest3 = ClassDocImpl.create(
+                CLASS.publicClassWithNests$Nest1$Nest2$Nest3, context);
+        innerClasses = ClassDocImpl.create(CLASS.innerClasses, context);
+
+        constructors = ClassDocImpl.create(CLASS.constructors, context);
+
+        implementsSerializable = ClassDocImpl.create(CLASS.implementsSerializable, context);
+        implementsExternalizable = ClassDocImpl.create(CLASS.implementsExternalizable, context);
+        serializable = ClassDocImpl.create(INTERFACE.serializable, context);
+        extendsSerializable = ClassDocImpl.create(INTERFACE.extendsSerializable, context);
+        extendsExternalizable = ClassDocImpl.create(INTERFACE.extendsExternalizable, context);
+
+        fieldsAccessModifiers = ClassDocImpl.create(CLASS.fieldsAccessModifiers, context);
+        methodsAccessModifiers = ClassDocImpl.create(CLASS.methodsAccessModifiers, context);
+    }
+
+    @Test
+    public void isClass() {
+        assertFalse(publicAnnotation.isClass());
+        assertFalse(publicInterface.isClass());
+
+        assertTrue(publicClass.isClass());
+        assertTrue(publicEnum.isClass());
+        assertTrue(javaLangObject.isClass());
+        assertTrue(javaLangError.isClass());
+        assertTrue(javaLangException.isClass());
+    }
+
+    @Test
+    public void isOrdinaryClass() {
+        // not an enumeration, interface, annotation, exception, or an error.
+        assertFalse(publicAnnotation.isOrdinaryClass());
+        assertFalse(publicEnum.isOrdinaryClass());
+        assertFalse(publicInterface.isOrdinaryClass());
+        assertFalse(javaLangError.isOrdinaryClass());
+        assertFalse(javaLangException.isOrdinaryClass());
+
+        assertTrue(publicClass.isOrdinaryClass());
+        assertTrue(javaLangObject.isOrdinaryClass());
+    }
+
+    @Test
+    public void isEnum() {
+        assertTrue(publicEnum.isEnum());
+
+        assertFalse(publicAnnotation.isEnum());
+        assertFalse(publicClass.isEnum());
+        assertFalse(publicInterface.isEnum());
+        assertFalse(javaLangError.isEnum());
+        assertFalse(javaLangException.isEnum());
+        assertFalse(javaLangObject.isEnum());
+    }
+
+    @Test
+    public void isInterface() {
+        assertTrue(publicInterface.isInterface());
+
+        assertFalse(publicAnnotation.isInterface());
+        assertFalse(publicClass.isInterface());
+        assertFalse(publicEnum.isInterface());
+        assertFalse(javaLangError.isInterface());
+        assertFalse(javaLangException.isInterface());
+        assertFalse(javaLangObject.isInterface());
+    }
+
+    @Test
+    public void isException() {
+        assertTrue(javaLangException.isException());
+
+        assertFalse(publicAnnotation.isException());
+        assertFalse(publicClass.isException());
+        assertFalse(publicEnum.isException());
+        assertFalse(publicInterface.isException());
+        assertFalse(javaLangError.isException());
+        assertFalse(javaLangObject.isException());
+    }
+
+    @Test
+    public void isError() {
+        assertTrue(javaLangError.isError());
+
+        assertFalse(publicAnnotation.isError());
+        assertFalse(publicClass.isError());
+        assertFalse(publicEnum.isError());
+        assertFalse(publicInterface.isError());
+        assertFalse(javaLangException.isError());
+        assertFalse(javaLangObject.isError());
+    }
+
+    @Test
+    public void name() {
+        assertEquals("AbstractEmptyClass", abstractEmptyClass.name());
+        assertEquals("AbstractEmptyInterface", abstractEmptyInterface.name());
+        assertEquals("PublicInterface", publicInterface.name());
+        assertEquals("PublicAnnotation", publicAnnotation.name());
+        assertEquals("PublicClass", publicClass.name());
+        assertEquals("PublicEnum", publicEnum.name());
+
+        assertEquals("Error", javaLangError.name());
+        assertEquals("Exception", javaLangException.name());
+        assertEquals("Object", javaLangObject.name());
+
+        assertEquals("PublicClassWithNests", publicClassWithNests.name());
+        assertEquals("PublicClassWithNests.Nest1", publicClassWithNests$Nest1.name());
+        assertEquals("PublicClassWithNests.Nest1.Nest2", publicClassWithNests$Nest1$Nest2.name());
+    }
+
+    @Test
+    public void qualifiedName() {
+        assertEquals("com.example.classes.AbstractEmptyClass", abstractEmptyClass.qualifiedName());
+        assertEquals("com.example.classes.AbstractEmptyInterface",
+                abstractEmptyInterface.qualifiedName());
+        assertEquals("com.example.classes.PublicInterface", publicInterface.qualifiedName());
+        assertEquals("com.example.classes.PublicAnnotation", publicAnnotation.qualifiedName());
+        assertEquals("com.example.classes.PublicClass", publicClass.qualifiedName());
+        assertEquals("com.example.classes.PublicEnum", publicEnum.qualifiedName());
+
+        assertEquals("java.lang.Error", javaLangError.qualifiedName());
+        assertEquals("java.lang.Exception", javaLangException.qualifiedName());
+        assertEquals("java.lang.Object", javaLangObject.qualifiedName());
+
+        assertEquals("com.example.classes.PublicClassWithNests",
+                publicClassWithNests.qualifiedName());
+        assertEquals("com.example.classes.PublicClassWithNests.Nest1",
+                publicClassWithNests$Nest1.qualifiedName());
+        assertEquals("com.example.classes.PublicClassWithNests.Nest1.Nest2",
+                publicClassWithNests$Nest1$Nest2.qualifiedName());
+    }
+
+    /**
+     * @see #constructors()
+     */
+    @Test
+    public void isIncluded() {
+        assertTrue(publicClass.isIncluded());
+
+        assertFalse(packagePrivateClass.isIncluded());
+    }
+
+    @Test
+    public void isAbstract() {
+        assertTrue(abstractEmptyClass.isAbstract());
+        assertTrue(abstractEmptyInterface.isAbstract());
+        assertTrue(publicInterface.isAbstract());
+        assertTrue(publicAnnotation.isAbstract());
+
+        assertFalse(publicClass.isAbstract());
+        assertFalse(publicEnum.isAbstract());
+        assertFalse(javaLangError.isAbstract());
+        assertFalse(javaLangException.isAbstract());
+        assertFalse(javaLangObject.isAbstract());
+    }
+
+    @Test
+    public void isSerializable() {
+        // Classes
+        assertTrue(implementsSerializable.isSerializable());
+        assertTrue(implementsExternalizable.isSerializable());
+
+        assertFalse(javaLangObject.isSerializable());
+
+        // Interfaces
+        assertTrue(extendsSerializable.isSerializable());
+        assertTrue(extendsExternalizable.isSerializable());
+    }
+
+    @Test
+    public void isExternalizable() {
+        // Classes
+        assertTrue(implementsExternalizable.isExternalizable());
+
+        assertFalse(implementsSerializable.isExternalizable());
+        assertFalse(javaLangObject.isExternalizable());
+
+        // Interfaces
+        assertTrue(extendsExternalizable.isExternalizable());
+
+        assertFalse(extendsSerializable.isExternalizable());
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void serializationMethods() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void serializableFields() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void definesSerializableFields() {
+    }
+
+    @Test
+    public void superclass() {
+        // a) interfaces (always null)
+        assertNull(publicInterface.superclass());
+
+        // b) classes
+        // 1. Object (no superclass)
+        assertNull(javaLangObject.superclass());
+        // 2. Object <- PublicClass
+        assertEquals(javaLangObject, publicClass.superclass());
+        // 3. Object <- Throwable <- Error
+        assertEquals(javaLangThrowable, javaLangError.superclass());
+        assertNotEquals(javaLangObject, javaLangError.superclass());
+        assertEquals(javaLangObject, javaLangError.superclass().superclass());
+    }
+
+    @Test
+    public void superclassType() {
+        // a) interfaces (always null)
+        assertNull(publicInterface.superclassType());
+
+        // b) classes
+        // 1. Object (no superclass)
+        assertNull(javaLangObject.superclassType());
+        // 2. Object <- PublicClass
+        assertEquals("java.lang.Object", publicClass.superclassType().qualifiedTypeName());
+        // 3. Object <- Throwable <- Error
+        assertEquals("java.lang.Throwable", javaLangError.superclassType().qualifiedTypeName());
+        assertNotEquals("java.lang.Object", javaLangError.superclassType().qualifiedTypeName());
+    }
+
+    @Test
+    public void subclassOf() {
+        // 1. Class is subclass of itself
+        assertTrue(javaLangObject.subclassOf(javaLangObject));
+        assertTrue(javaLangError.subclassOf(javaLangError));
+        assertTrue(publicClass.subclassOf(publicClass));
+
+        // 2. Class is subclass of java.lang.Object
+        assertTrue(javaLangError.subclassOf(javaLangObject));
+        assertTrue(publicClass.subclassOf(javaLangObject));
+
+        // 3. Interface is subclass of java.lang.Object *only*
+        assertTrue(publicInterface.subclassOf(javaLangObject));
+        assertFalse(publicInterface.subclassOf(publicInterface));
+        assertFalse(extendsExternalizable.subclassOf(extendsSerializable));
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void interfaces() {
+    }
+
+    @Test
+    public void interfaceTypes() {
+        // a) interfaces
+        // 1. Serializable
+        var types = serializable.interfaceTypes();
+        assertArrayEmpty(types);
+
+        // 2. Interface extends Serializable
+        types = extendsSerializable.interfaceTypes();
+        assertEquals(1, types.length);
+        assertEquals("java.io.Serializable", types[0].qualifiedTypeName());
+
+        // b) classes
+        // 1. Object does not implement any interface
+        types = javaLangObject.interfaceTypes();
+        assertArrayEmpty(types);
+
+        // 2. Class implements Serializable
+        types = implementsSerializable.interfaceTypes();
+        assertEquals(1, types.length);
+        assertEquals("java.io.Serializable", types[0].qualifiedTypeName());
+    }
+
+    @Test
+    public void typeParameters() {
+        var params = javaLangObject.typeParameters();
+        assertArrayEmpty(params);
+
+        params = javaUtilMap.typeParameters();
+        assertEquals(2, params.length);
+        assertEquals("K", params[0].simpleTypeName());
+        assertEquals("V", params[1].simpleTypeName());
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void typeParamTags() {
+    }
+
+    /**
+     * @implNote This (and also {@link #fields_filter()} and {@link #isIncluded()}) tests do not
+     * cover cases when Doclet is supplied with a non-default
+     * <b>selection control</b> flag (default is {@code -protected}), i.e. {@code -public}, {@code
+     * -package} or {@code -private}. It also does not currently cover selection control options
+     * from new Doclet API (e.g. {@code --show-members}.
+     * @see jdk.javadoc.doclet definition of <b>selection control</b> in "Terminology" section
+     * @see jdk.javadoc.doclet new options in "Options" section
+     */
+    @Test
+    public void fields() {
+        // 1. Class with four fields (public, protected, private and package-private).
+        // Should include only public and protected.
+        var classFields = fieldsAccessModifiers.fields();
+        assertEquals(2, classFields.length);
+
+        // 2. Public enum has no declared constructors, but has one implicit private.
+        var enumFields = publicEnum.fields();
+        assertArrayEmpty(enumFields);
+
+        //TODO: Handle all selection control variants.
+    }
+
+    /**
+     * @see #fields()
+     */
+    @Test
+    public void fields_filter() {
+        // 1. Class with four fields (public, protected, private and package-private).
+
+        // filter(true): Should include only public and protected.
+        var classFields = fieldsAccessModifiers.fields(true);
+        assertEquals(2, classFields.length);
+
+        // filter(false): Should include all four.
+        classFields = fieldsAccessModifiers.fields(false);
+        assertEquals(4, classFields.length);
+    }
+
+    @Test
+    public void enumConstants() {
+        assertArrayEmpty(publicClass.enumConstants());
+        assertArrayEmpty(publicInterface.enumConstants());
+        assertArrayEmpty(publicAnnotation.enumConstants());
+
+        FieldDoc[] constants = simpleEnum.enumConstants();
+        assertEquals(3, constants.length);
+        assertEquals("A", constants[0].name());
+        assertEquals("B", constants[1].name());
+        assertEquals("C", constants[2].name());
+    }
+
+    private static <T> void assertArrayEmpty(T[] array) {
+        assertEquals(0, array.length);
+    }
+
+    /**
+     * @implNote This (and also {@link #fields_filter()} and {@link #isIncluded()}) tests do not
+     * cover cases when Doclet is supplied with a non-default <b>selection control</b> flag (default
+     * is {@code -protected}), i.e. {@code -public}, {@code -package} or {@code -private}. It also
+     * does not currently cover selection control options from new Doclet API (e.g.
+     * {@code --show-members}.
+     * @see jdk.javadoc.doclet definition of <b>selection control</b> in "Terminology" section
+     * @see jdk.javadoc.doclet new options in "Options" section
+     */
+    @Test
+    public void methods() {
+        assertArrayEmpty(publicClass.methods());
+
+        // Class with 4 methods (public, protected, private and package-private).
+        // Should include only public and protected.
+        MethodDoc[] methods = methodsAccessModifiers.methods();
+        assertEquals(2, methods.length);
+    }
+
+    /**
+     * @see #methods()
+     */
+    @Test
+    public void methods_filter() {
+        // 1. Class with four methods (public, protected, private and package-private).
+
+        // filter(true): Should include only public and protected.
+        MethodDoc[] methods = methodsAccessModifiers.methods(true);
+        assertEquals(2, methods.length);
+
+        // filter(false): Should include all four.
+        methods = methodsAccessModifiers.methods(false);
+        assertEquals(4, methods.length);
+    }
+
+    /**
+     * @implNote This (and also {@link #constructors_filter_false()},
+     * {@link #constructors_filter_true()} and {@link #isIncluded()}) tests do not cover cases when
+     * Doclet is supplied with a non-default <b>selection control</b> flag (default is
+     * {@code -protected}), i.e. {@code -public}, {@code -package} or {@code -private}. It also does
+     * not currently cover selection control options from new Doclet API (e.g.
+     * {@code --show-members}.
+     * @see jdk.javadoc.doclet definition of <b>selection control</b> in "Terminology" section
+     * @see jdk.javadoc.doclet new options in "Options" section
+     */
+    @Test
+    public void constructors() {
+        // 1. Class with four constructors (public, protected, private and package-private).
+        // Should include only public and protected.
+        var ctors = constructors.constructors();
+        assertEquals(2, ctors.length);
+
+        // 2. Public enum has no declared constructors, but has one implicit private.
+        var enumConstructors = publicEnum.constructors();
+        assertArrayEmpty(enumConstructors);
+
+        //TODO: Handle all selection control variants.
+    }
+
+    /**
+     * @see #constructors()
+     */
+    @Test
+    public void constructors_filter_true() {
+        // 1. Class with four constructors (public, protected, private and package-private).
+        // Should include only public and protected.
+        var ctors = constructors.constructors(true);
+        assertEquals(2, ctors.length);
+
+        // 2. Public enum has no declared constructors, but has one implicit private.
+        var enumConstructors = publicEnum.constructors(true);
+        assertArrayEmpty(enumConstructors);
+    }
+
+    /**
+     * @see #constructors()
+     */
+    @Test
+    public void constructors_filter_false() {
+        // 1. Class with four constructors (public, protected, private and package-private).
+        // Should include all four.
+        var ctors = constructors.constructors(false);
+        assertEquals(4, ctors.length);
+
+        // 2. Public enum has no declared constructors, but has one implicit private.
+        var enumConstructors = publicEnum.constructors(false);
+        assertEquals(1, enumConstructors.length);
+    }
+
+    @Test
+    public void innerClasses() {
+        // Test is intentionally empty as it innerClasses() is effectively innerClasses(true) and
+        // is covered in #innerClasses_filter_true().
+    }
+
+    /**
+     * @implNote This (and also {@link #innerClasses_filter_false()}, and {@link #isIncluded()})
+     * tests do not cover cases when Doclet is supplied with a non-default <b>selection control</b>
+     * flag (default is {@code -protected}), i.e. {@code -public}, {@code -package} or
+     * {@code -private}. It also does not currently cover selection control options from new Doclet
+     * API (e.g. {@code --show-members}.
+     * @see jdk.javadoc.doclet definition of <b>selection control</b> in "Terminology" section
+     * @see jdk.javadoc.doclet new options in "Options" section
+     */
+    @Test
+    public void innerClasses_filter_true() {
+        // 1. No inner classes
+        assertArrayEmpty(publicAnnotation.innerClasses(true));
+        assertArrayEmpty(publicClass.innerClasses(true));
+        assertArrayEmpty(publicEnum.innerClasses(true));
+        assertArrayEmpty(publicInterface.innerClasses(true));
+
+        // 2. innerClasses() should return only immediate inner classes.
+        /*
+        public class PublicClassWithNests {
+            public class Nest1 {
+                public class Nest2 {
+                    public class Nest3 {
+                    }
+                }
+            }
+        }
+         */
+        assertArrayEquals(new String[]{"PublicClassWithNests.Nest1"},
+                getInnerClassesNames(publicClassWithNests, true));
+        assertArrayEquals(new String[]{"PublicClassWithNests.Nest1.Nest2"},
+                getInnerClassesNames(publicClassWithNests$Nest1, true));
+        assertArrayEquals(new String[]{"PublicClassWithNests.Nest1.Nest2.Nest3"},
+                getInnerClassesNames(publicClassWithNests$Nest1$Nest2, true));
+        assertArrayEmpty(getInnerClassesNames(publicClassWithNests$Nest1$Nest2$Nest3, true));
+
+        // InnerClasses has 16 inner classes:
+        // {public,private,protected,package-private}
+        // x
+        // {annotation,class,enum,interface}
+
+        // 3. innerClasses() should return only classes and interfaces (no annotations/enums).
+        assertTrue(Arrays.stream(innerClasses.innerClasses(true))
+                .allMatch(cls -> cls.isClass() || cls.isInterface())
+        );
+
+        // 4. innerClasses() should return only public/protected/package-private (no private).
+        assertTrue(Arrays.stream(innerClasses.innerClasses(true))
+                .allMatch(cls -> cls.isPublic() || cls.isProtected() || cls.isPackagePrivate())
+        );
+    }
+
+    @Test
+    public void innerClasses_filter_false() {
+        // 1. No inner classes
+        assertArrayEmpty(publicAnnotation.innerClasses(false));
+        assertArrayEmpty(publicClass.innerClasses(false));
+        assertArrayEmpty(publicEnum.innerClasses(false));
+        assertArrayEmpty(publicInterface.innerClasses(false));
+
+        // 2. innerClasses() should return only immediate inner classes.
+        /*
+        public class PublicClassWithNests {
+            public class Nest1 {
+                public class Nest2 {
+                    public class Nest3 {
+                    }
+                }
+            }
+        }
+         */
+        assertArrayEquals(new String[]{"PublicClassWithNests.Nest1"},
+                getInnerClassesNames(publicClassWithNests, false));
+        assertArrayEquals(new String[]{"PublicClassWithNests.Nest1.Nest2"},
+                getInnerClassesNames(publicClassWithNests$Nest1, false));
+        assertArrayEquals(new String[]{"PublicClassWithNests.Nest1.Nest2.Nest3"},
+                getInnerClassesNames(publicClassWithNests$Nest1$Nest2, false));
+        assertArrayEmpty(getInnerClassesNames(publicClassWithNests$Nest1$Nest2$Nest3, false));
+
+        // InnerClasses has 16 inner classes:
+        // {public,private,protected,package-private}
+        // x
+        // {annotation,class,enum,interface}
+
+        // 3. innerClasses() should return only classes and interfaces (no annotations/enums).
+        assertTrue(Arrays.stream(innerClasses.innerClasses(false))
+                .allMatch(cls -> cls.isClass() || cls.isInterface())
+        );
+
+        // 4. innerClasses() should return all (public/protected/package-private/private).
+        assertTrue(Arrays.stream(innerClasses.innerClasses(false))
+                .allMatch(cls -> cls.isPublic() || cls.isProtected() || cls.isPackagePrivate()
+                        || cls.isPrivate())
+        );
+    }
+
+    private static String[] getInnerClassesNames(ClassDocImpl cls, boolean filter) {
+        return Arrays.stream(cls.innerClasses(filter))
+                .map(ProgramElementDoc::name)
+                .toArray(String[]::new);
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void findClass() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void importedClasses() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void importedPackages() {
+    }
+
+    @Test
+    public void typeName() {
+        assertEquals("AbstractEmptyClass", abstractEmptyClass.typeName());
+        assertEquals("AbstractEmptyInterface", abstractEmptyInterface.typeName());
+        assertEquals("PublicInterface", publicInterface.typeName());
+        assertEquals("PublicAnnotation", publicAnnotation.typeName());
+        assertEquals("PublicClass", publicClass.typeName());
+        assertEquals("PublicEnum", publicEnum.typeName());
+
+        assertEquals("Error", javaLangError.typeName());
+        assertEquals("Exception", javaLangException.typeName());
+        assertEquals("Object", javaLangObject.typeName());
+
+        assertEquals("PublicClassWithNests", publicClassWithNests.typeName());
+        assertEquals("PublicClassWithNests.Nest1", publicClassWithNests$Nest1.typeName());
+        assertEquals("PublicClassWithNests.Nest1.Nest2",
+                publicClassWithNests$Nest1$Nest2.typeName());
+    }
+
+    @Test
+    public void qualifiedTypeName() {
+        assertEquals("com.example.classes.AbstractEmptyClass",
+                abstractEmptyClass.qualifiedTypeName());
+        assertEquals("com.example.classes.AbstractEmptyInterface",
+                abstractEmptyInterface.qualifiedName());
+        assertEquals("com.example.classes.PublicInterface", publicInterface.qualifiedName());
+        assertEquals("com.example.classes.PublicAnnotation", publicAnnotation.qualifiedName());
+        assertEquals("com.example.classes.PublicClass", publicClass.qualifiedName());
+        assertEquals("com.example.classes.PublicEnum", publicEnum.qualifiedName());
+
+        assertEquals("java.lang.Error", javaLangError.qualifiedName());
+        assertEquals("java.lang.Exception", javaLangException.qualifiedName());
+        assertEquals("java.lang.Object", javaLangObject.qualifiedName());
+
+        assertEquals("com.example.classes.PublicClassWithNests",
+                publicClassWithNests.qualifiedName());
+        assertEquals("com.example.classes.PublicClassWithNests.Nest1",
+                publicClassWithNests$Nest1.qualifiedName());
+        assertEquals("com.example.classes.PublicClassWithNests.Nest1.Nest2",
+                publicClassWithNests$Nest1$Nest2.qualifiedName());
+
+        assertEquals("java.util.Map", javaUtilMap.qualifiedTypeName());
+    }
+
+    @Test
+    public void simpleTypeName() {
+        assertEquals("AbstractEmptyClass", abstractEmptyClass.simpleTypeName());
+        assertEquals("AbstractEmptyInterface", abstractEmptyInterface.simpleTypeName());
+        assertEquals("PublicInterface", publicInterface.simpleTypeName());
+        assertEquals("PublicAnnotation", publicAnnotation.simpleTypeName());
+        assertEquals("PublicClass", publicClass.simpleTypeName());
+        assertEquals("PublicEnum", publicEnum.simpleTypeName());
+
+        assertEquals("Error", javaLangError.simpleTypeName());
+        assertEquals("Exception", javaLangException.simpleTypeName());
+        assertEquals("Object", javaLangObject.simpleTypeName());
+
+        assertEquals("PublicClassWithNests", publicClassWithNests.simpleTypeName());
+        assertEquals("Nest1", publicClassWithNests$Nest1.simpleTypeName());
+        assertEquals("Nest2", publicClassWithNests$Nest1$Nest2.simpleTypeName());
+    }
+
+    @Test
+    public void dimension() {
+        assertEquals("", publicClass.dimension());
+    }
+
+    @Test
+    public void isPrimitive() {
+        assertFalse(publicClass.isPrimitive());
+        assertFalse(publicInterface.isPrimitive());
+        assertFalse(publicEnum.isPrimitive());
+    }
+
+    @Test
+    public void asClassDoc() {
+        assertEquals(publicClass, publicClass.asClassDoc());
+        assertEquals(publicInterface, publicInterface.asClassDoc());
+        assertEquals(publicEnum, publicEnum.asClassDoc());
+    }
+
+    @Test
+    public void asParameterizedType() {
+        assertNull(publicClass.asParameterizedType());
+        assertNull(publicInterface.asParameterizedType());
+        assertNull(publicEnum.asParameterizedType());
+    }
+
+    @Test
+    public void asTypeVariable() {
+        assertNull(publicClass.asTypeVariable());
+        assertNull(publicInterface.asTypeVariable());
+        assertNull(publicEnum.asTypeVariable());
+    }
+
+    @Test
+    public void asWildcardType() {
+        assertNull(publicClass.asWildcardType());
+        assertNull(publicInterface.asWildcardType());
+        assertNull(publicEnum.asWildcardType());
+    }
+
+    @Test
+    public void asAnnotatedType() {
+        assertNull(publicClass.asAnnotatedType());
+        assertNull(publicInterface.asAnnotatedType());
+        assertNull(publicEnum.asAnnotatedType());
+    }
+
+    @Test
+    public void asAnnotationTypeDoc() {
+        assertNull(publicClass.asAnnotationTypeDoc());
+        assertNull(publicInterface.asAnnotationTypeDoc());
+        assertNull(publicEnum.asAnnotationTypeDoc());
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void getElementType() {
+    }
+
+    @Test
+    public void modifiers() {
+        assertEquals("public abstract", abstractEmptyClass.modifiers());
+        assertEquals("public", publicClass.modifiers());
+        assertEquals("public final", publicEnum.modifiers());
+
+        // interfaces and annotations should not have 'abstract' modifier
+        assertEquals("public interface", publicInterface.modifiers());
+        assertEquals("public interface", publicAnnotation.modifiers());
+    }
+
+    @Test
+    public void modifierSpecifier() {
+        assertEquals(Modifier.PUBLIC | Modifier.ABSTRACT,
+                abstractEmptyClass.modifierSpecifier());
+        assertEquals(Modifier.PUBLIC, publicClass.modifierSpecifier());
+        assertEquals(Modifier.PUBLIC | Modifier.FINAL, publicEnum.modifierSpecifier());
+
+        // interfaces and annotations should not have 'abstract' modifier
+        assertEquals(Modifier.PUBLIC | Modifier.INTERFACE, publicInterface.modifierSpecifier());
+        assertEquals(Modifier.PUBLIC | Modifier.INTERFACE, publicAnnotation.modifierSpecifier());
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/ConstructorDocImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/ConstructorDocImplTest.java
new file mode 100644
index 0000000..e4da9be
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/ConstructorDocImplTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class ConstructorDocImplTest extends BaseTest {
+
+    private ConstructorDocImpl empty;
+    private ConstructorDocImpl arg1_int;
+    private ConstructorDocImpl arg1_String;
+    private ConstructorDocImpl arg2_int_String;
+
+    @Override
+    public void setUp() {
+        super.setUp();
+        empty = ConstructorDocImpl.create(CONSTRUCTOR.empty, context);
+        arg1_int = ConstructorDocImpl.create(CONSTRUCTOR.arg1_int, context);
+        arg1_String = ConstructorDocImpl.create(CONSTRUCTOR.arg1_String, context);
+        arg2_int_String = ConstructorDocImpl.create(CONSTRUCTOR.arg2_int_String, context);
+    }
+
+    @Test
+    public void isConstructor() {
+        assertTrue(empty.isConstructor());
+        assertTrue(arg1_int.isConstructor());
+        assertTrue(arg1_String.isConstructor());
+        assertTrue(arg2_int_String.isConstructor());
+    }
+
+    @Test
+    public void name() {
+        assertEquals("Constructors", empty.name());
+        assertEquals("Constructors", arg1_int.name());
+        assertEquals("Constructors", arg1_String.name());
+        assertEquals("Constructors", arg2_int_String.name());
+    }
+
+    @Test
+    public void qualifiedName() {
+        assertEquals("com.example.constructors.Constructors", empty.qualifiedName());
+        assertEquals("com.example.constructors.Constructors", arg1_int.qualifiedName());
+        assertEquals("com.example.constructors.Constructors", arg1_String.qualifiedName());
+        assertEquals("com.example.constructors.Constructors", arg2_int_String.qualifiedName());
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/DocImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/DocImplTest.java
new file mode 100644
index 0000000..27c9309
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/DocImplTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.assertEquals;
+
+import com.sun.javadoc.Tag;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class DocImplTest extends BaseTest {
+
+    private ClassDocImpl see;
+    private ClassDocImpl throwz;
+    private ClassDocImpl various;
+
+    @Before
+    public void setUp() {
+        super.setUp();
+
+        see = ClassDocImpl.create(CLASS.tags$See, context);
+        throwz = ClassDocImpl.create(CLASS.tags$Throws, context);
+        various = ClassDocImpl.create(CLASS.tags$Various, context);
+    }
+
+    @Test
+    public void commentText() {
+        assertEquals("", see.commentText());
+        assertEquals("", throwz.commentText());
+        assertEquals("""
+                        First sentence of the class that consists of three tags: text, inline ({@code something})
+                         and text. Then goes the second sentence of class javadoc. It is followed by a third
+                         sentence that has some inline tags, such as {@code some code},
+                         {@link java.lang.Integer label} and {@linkplain java.lang.Byte label}.""",
+                various.commentText());
+    }
+
+    @Test
+    public void tags() {
+        assertEquals(3, see.tags().length);
+        assertEquals(2, throwz.tags().length);
+        assertEquals(4, various.tags().length);
+    }
+
+    @Test
+    public void tags_ofKind() {
+        assertEquals(3, see.tags("@see").length);
+        assertEquals(0, see.tags("@throws").length);
+
+        assertEquals(2, throwz.tags("@throws").length);
+        assertEquals(0, throwz.tags("@see").length);
+
+        assertEquals(1, various.tags("@see").length);
+        assertEquals(0, various.tags("@custom").length);
+    }
+
+    @Test
+    public void seeTags() {
+        assertEquals(3, see.seeTags().length);
+        assertEquals(0, throwz.seeTags().length);
+        assertEquals(1, various.seeTags().length);
+    }
+
+    @Test
+    public void inlineTags() {
+        Tag[] inlineTags = various.inlineTags();
+        assertEquals(9, inlineTags.length);
+
+        assertEquals("@text", inlineTags[0].name());
+        assertEquals("@code", inlineTags[1].name());
+        assertEquals("@text", inlineTags[2].name());
+        assertEquals("@code", inlineTags[3].name());
+        assertEquals("@text", inlineTags[4].name());
+        assertEquals("@link", inlineTags[5].name());
+        assertEquals("@text", inlineTags[6].name());
+        assertEquals("@linkplain", inlineTags[7].name());
+        assertEquals("@text", inlineTags[8].name());
+    }
+
+    @Test
+    public void firstSentenceTags() {
+        Tag[] fst = various.firstSentenceTags();
+        assertEquals(3, fst.length);
+        assertEquals("@text", fst[0].name());
+        assertEquals("First sentence of the class that consists of three tags: text, inline (",
+                fst[0].text());
+        assertEquals("@code", fst[1].name());
+        assertEquals("{@code something}", fst[1].text());
+
+        assertEquals("@text", fst[2].name());
+        assertEquals(")\n and text.", fst[2].text());
+    }
+
+    /**
+     * @see DocImpl#getRawCommentText()
+     */
+    @Test
+    public void getRawCommentText() {
+        // To be 1-1 compatible with previous implementation, this test case should be used:
+        String expectedIdentical = """
+                 First sentence of the class that consists of three tags: text, inline ({@code something})
+                 and text. Then goes the second sentence of class javadoc. It is followed by a third
+                 sentence that has some inline tags, such as {@code some code},
+                 {@link java.lang.Integer label} and {@linkplain java.lang.Byte label}.
+                                
+                 @author someone with a very long name
+                 @version version
+                 @see Throws
+                 @since 1.0
+                """;
+
+        // This is a "prettified" version which is produced by new implementation.
+        String expected = """
+                First sentence of the class that consists of three tags: text, inline ({@code something})
+                 and text. Then goes the second sentence of class javadoc. It is followed by a third
+                 sentence that has some inline tags, such as {@code some code},
+                 {@link java.lang.Integer label} and {@linkplain java.lang.Byte label}.
+                @author someone with a very long name
+                @version version
+                @see Throws
+                @since 1.0""";
+
+        String actual = various.getRawCommentText();
+
+        assertEquals(expected, actual);
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void setRawCommentText() {
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/EmptyDoclet.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/EmptyDoclet.java
new file mode 100644
index 0000000..f0c42f8
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/EmptyDoclet.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.stream.Stream;
+import javax.lang.model.SourceVersion;
+import jdk.javadoc.doclet.Doclet;
+import jdk.javadoc.doclet.DocletEnvironment;
+import jdk.javadoc.doclet.Reporter;
+
+/**
+ * Doclet for unit testing implementation classes {@link com.google.doclava.javadoc}. Its sole
+ * purpose is to produce {@link DocletEnvironment} from a given source path and cache it, so it can
+ * be used by the rest of the unit tests.
+ *
+ * @see BaseTest
+ */
+public class EmptyDoclet implements Doclet {
+
+    // Has to be static, otherwise gc'ed before tests are run.
+    private static DocletEnvironment environment;
+
+    // jdk.javadoc.internal.tool.Main.execute(...) requires empty constructor.
+    public EmptyDoclet() {
+    }
+
+    public EmptyDoclet(String sourcesPath) {
+        try {
+            PrintWriter out = new PrintWriter(Writer.nullWriter());
+            StringWriter sw = new StringWriter();
+            PrintWriter err = new PrintWriter(new BufferedWriter(sw));
+
+            Method execute = jdk.javadoc.internal.tool.Main.class.getMethod("execute",
+                    String[].class, PrintWriter.class, PrintWriter.class);
+            execute.setAccessible(true);
+
+            List<String> args = new ArrayList<>(List.of(
+                    "-encoding", "UTF-8",
+                    "-doclet", "com.google.doclava.javadoc.EmptyDoclet"
+            ));
+
+            try (Stream<Path> walk = Files.walk(Path.of(sourcesPath))) {
+                var files = walk
+                        .filter(f -> Files.isRegularFile(f) && f.toString().endsWith(".java"))
+                        .map(Path::toString)
+                        .toList();
+                args.addAll(files);
+            } catch (IOException e) {
+                throw new RuntimeException("Invalid path to run doclet onm: " + e);
+            }
+
+            String[] stringArgs = args.toArray(String[]::new);
+
+            Integer result = (Integer) execute.invoke(null, stringArgs, out, err);
+            if (result != 0) {
+                System.err.println(sw);
+                throw new RuntimeException("Failed to run Doclet: " + result);
+            }
+        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
+            throw new RuntimeException("Failed to run Doclet: " + e);
+        }
+    }
+
+    @Override
+    public void init(Locale locale, Reporter reporter) {
+    }
+
+    @Override
+    public String getName() {
+        return "Stub doclet for unit testing of the com.google.doclava.Doclava doclet";
+    }
+
+    @Override
+    public Set<? extends Option> getSupportedOptions() {
+        return Set.of();
+    }
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.RELEASE_17;
+    }
+
+    @Override
+    public boolean run(DocletEnvironment environment) {
+        EmptyDoclet.environment = environment;
+        return true;
+    }
+
+    public DocletEnvironment getEnvironment() {
+        return environment;
+    }
+}
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/ExecutableMemberDocImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/ExecutableMemberDocImplTest.java
new file mode 100644
index 0000000..9e4aad3
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/ExecutableMemberDocImplTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.assertFalse;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class ExecutableMemberDocImplTest extends BaseTest {
+
+    private ConstructorDocImpl empty;
+
+    @Before
+    public void setUp() {
+        super.setUp();
+        empty = ConstructorDocImpl.create(CONSTRUCTOR.empty, context);
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void isNative() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void isSynchronized() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void isVarArgs() {
+    }
+
+    @Test
+    public void isSynthetic() {
+        assertFalse(empty.isSynthetic());
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void isIncluded() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void throwsTags() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void paramTags() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void typeParamTags() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void thrownExceptions() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void thrownExceptionTypes() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void parameters() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void receiverType() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void typeParameters() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void signature() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void flatSignature() {
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/FieldDocImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/FieldDocImplTest.java
new file mode 100644
index 0000000..0438959
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/FieldDocImplTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class FieldDocImplTest extends BaseTest {
+
+    private FieldDocImpl public_int;
+    private FieldDocImpl public_transient_volatile_Object;
+    private FieldDocImpl public_final_int;
+    private FieldDocImpl public_final_String;
+
+    @Before
+    public void setUp() {
+        super.setUp();
+        public_int = FieldDocImpl.create(FIELD.public_int, context);
+        public_transient_volatile_Object =
+                FieldDocImpl.create(FIELD.public_transient_volatile_Object, context);
+        public_final_int = FieldDocImpl.create(FIELD.public_final_int, context);
+        public_final_String = FieldDocImpl.create(FIELD.public_final_String, context);
+    }
+
+    @Test
+    public void isSynthetic() {
+        assertFalse(public_int.isSynthetic());
+        assertFalse(public_transient_volatile_Object.isSynthetic());
+        assertFalse(public_final_int.isSynthetic());
+        assertFalse(public_final_String.isSynthetic());
+        // DocletEnvironment does not contain/handle any synthetic fields.
+    }
+
+    @Test
+    public void name() {
+        assertEquals("public_int", public_int.name());
+        assertEquals("public_transient_volatile_Object", public_transient_volatile_Object.name());
+        assertEquals("public_final_int", public_final_int.name());
+        assertEquals("public_final_String", public_final_String.name());
+    }
+
+    @Test
+    public void qualifiedName() {
+        assertEquals("com.example.fields.Fields.public_int", public_int.qualifiedName());
+        assertEquals("com.example.fields.Fields.public_transient_volatile_Object",
+                public_transient_volatile_Object.qualifiedName());
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void isIncluded() {
+    }
+
+    @Test
+    public void type() {
+        assertEquals(PrimitiveTypeImpl.INT, public_int.type());
+        assertEquals(ClassDocImpl.create(INSTANCE.javaLangObject, context),
+                public_transient_volatile_Object.type());
+    }
+
+    @Test
+    public void isTransient() {
+        assertFalse(public_int.isTransient());
+        assertTrue(public_transient_volatile_Object.isTransient());
+    }
+
+    @Test
+    public void isVolatile() {
+        assertFalse(public_int.isVolatile());
+        assertTrue(public_transient_volatile_Object.isVolatile());
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void serialFieldTags() {
+    }
+
+    @Test
+    public void constantValue() {
+        assertNull(public_int.constantValue());
+        assertNull(public_transient_volatile_Object.constantValue());
+
+        assertEquals(public_final_int.constantValue(), Integer.valueOf(5));
+        assertEquals(public_final_String.constantValue(), "abc");
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void constantValueExpression() {
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/MethodDocImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/MethodDocImplTest.java
new file mode 100644
index 0000000..b504e40
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/MethodDocImplTest.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.doclava.javadoc.BaseTest.METHOD.OF_CLASS;
+import com.google.doclava.javadoc.BaseTest.METHOD.OF_INTERFACE;
+import com.google.doclava.javadoc.BaseTest.METHOD.OVERRIDES;
+import com.sun.javadoc.MethodDoc;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class MethodDocImplTest extends BaseTest {
+
+    private static class CLASS_METHOD {
+
+        public static MethodDocImpl public_void_arg0;
+        public static MethodDocImpl private_int_arg0;
+        public static MethodDocImpl packagePrivate_String_arg2_int_String;
+        public static MethodDocImpl public_abstract_void_arg0;
+        public static MethodDocImpl override_public_String_toString0;
+    }
+
+    private static class INTERFACE_METHOD {
+
+        public static MethodDocImpl public_void_arg0;
+        public static MethodDocImpl public_default_String_arg0;
+    }
+
+    private static class OVERRIDE {
+
+        public static MethodDocImpl A;
+        public static MethodDocImpl B;
+        public static MethodDocImpl C;
+        public static MethodDocImpl D;
+    }
+
+    private ClassDocImpl javaLangString;
+
+    @Override
+    public void setUp() {
+        super.setUp();
+        CLASS_METHOD.public_void_arg0 = MethodDocImpl.create(OF_CLASS.public_void_arg0, context);
+        CLASS_METHOD.private_int_arg0 = MethodDocImpl.create(OF_CLASS.private_int_arg0, context);
+        CLASS_METHOD.packagePrivate_String_arg2_int_String = MethodDocImpl.create(
+                OF_CLASS.packagePrivate_String_arg2_int_String, context);
+        CLASS_METHOD.public_abstract_void_arg0 = MethodDocImpl.create(
+                OF_CLASS.public_abstract_void_arg0, context);
+        CLASS_METHOD.override_public_String_toString0 = MethodDocImpl.create(
+                OF_CLASS.override_public_String_toString0, context);
+
+        INTERFACE_METHOD.public_void_arg0 = MethodDocImpl.create(OF_INTERFACE.public_void_arg0,
+                context);
+        INTERFACE_METHOD.public_default_String_arg0 =
+                MethodDocImpl.create(OF_INTERFACE.public_default_String_arg0, context);
+
+        OVERRIDE.A = MethodDocImpl.create(OVERRIDES.A_name, context);
+        OVERRIDE.B = MethodDocImpl.create(OVERRIDES.B_name, context);
+        OVERRIDE.C = MethodDocImpl.create(OVERRIDES.C_name, context);
+        OVERRIDE.D = MethodDocImpl.create(OVERRIDES.D_name, context);
+
+        javaLangString = ClassDocImpl.create(INSTANCE.javaLangString, context);
+    }
+
+    @Test
+    public void name() {
+        assertEquals("public_void_arg0", CLASS_METHOD.public_void_arg0.name());
+        assertEquals("public_default_String_arg0",
+                INTERFACE_METHOD.public_default_String_arg0.name());
+    }
+
+    @Test
+    public void qualifiedName() {
+        assertEquals("com.example.methods.OfClass.public_void_arg0",
+                CLASS_METHOD.public_void_arg0.qualifiedName());
+        assertEquals("com.example.methods.OfInterface.public_default_String_arg0",
+                INTERFACE_METHOD.public_default_String_arg0.qualifiedName());
+    }
+
+    @Test
+    public void isMethod() {
+        assertTrue(CLASS_METHOD.public_void_arg0.isMethod());
+        assertTrue(INTERFACE_METHOD.public_void_arg0.isMethod());
+    }
+
+    @Test
+    public void isAbstract() {
+        assertFalse(CLASS_METHOD.public_void_arg0.isAbstract());
+        // default interface method is not abstract
+        assertFalse(INTERFACE_METHOD.public_default_String_arg0.isAbstract());
+
+        assertTrue(CLASS_METHOD.public_abstract_void_arg0.isAbstract());
+        // interface methods are abstract
+        assertTrue(INTERFACE_METHOD.public_void_arg0.isAbstract());
+    }
+
+    @Test
+    public void isDefault() {
+        assertFalse(CLASS_METHOD.public_void_arg0.isDefault());
+        assertFalse(CLASS_METHOD.public_abstract_void_arg0.isDefault());
+
+        assertTrue(INTERFACE_METHOD.public_default_String_arg0.isDefault());
+    }
+
+    @Test
+    public void returnType() {
+        assertEquals(PrimitiveTypeImpl.VOID, CLASS_METHOD.public_void_arg0.returnType());
+        assertEquals(PrimitiveTypeImpl.INT, CLASS_METHOD.private_int_arg0.returnType());
+        assertEquals(javaLangString, CLASS_METHOD.override_public_String_toString0.returnType());
+
+        assertEquals(javaLangString, INTERFACE_METHOD.public_default_String_arg0.returnType());
+        assertEquals(PrimitiveTypeImpl.VOID, INTERFACE_METHOD.public_void_arg0.returnType());
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void overriddenClass() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void overriddenType() {
+    }
+
+    @Test
+    public void overriddenMethod() {
+        assertNull(CLASS_METHOD.public_void_arg0.overriddenMethod());
+
+        MethodDoc overrides_String_toString =
+                CLASS_METHOD.override_public_String_toString0.overriddenMethod();
+        assertEquals("java.lang.Object.toString", overrides_String_toString.qualifiedName());
+
+        // Fixtures from com.example.methods.override
+        // A <- B <- C
+        // ^
+        // |
+        // D
+
+        var a = OVERRIDE.A;
+        var b = OVERRIDE.B;
+        var c = OVERRIDE.C;
+        var d = OVERRIDE.D;
+
+        // Positive cases (A <- B; B <- C; A <- D)
+        assertEquals(a, b.overriddenMethod());
+        assertEquals(b, c.overriddenMethod());
+        assertEquals(a, d.overriddenMethod());
+
+        // Negative cases
+        // 1. Top-level class is not extending (and overriding) anything.
+        assertNull(a.overriddenMethod());
+
+        // 2. Method never overrides itself.
+        assertNotEquals(a, a.overriddenMethod());
+        assertNotEquals(b, b.overriddenMethod());
+        assertNotEquals(c, c.overriddenMethod());
+        assertNotEquals(d, d.overriddenMethod());
+
+        // 3. Indirect overrides.
+        // *A* <- B <- *C* – A overrides C but *not* directly, there's B in between.
+        assertNotEquals(a, c.overriddenMethod());
+
+        // 4. Non-related methods (different classes).
+        assertNotEquals(a, CLASS_METHOD.override_public_String_toString0.overriddenMethod());
+
+        // 5. "Parent" does not override "child", i.e. method upper in hierarchy does not
+        //    override anything below.
+        assertNotEquals(b, a.overriddenMethod());
+        assertNotEquals(c, a.overriddenMethod());
+        assertNotEquals(d, a.overriddenMethod());
+
+        assertNotEquals(c, b.overriddenMethod());
+
+        // 6. Exhaust the rest of negative test cases
+        assertNotEquals(b, d.overriddenMethod());
+        assertNotEquals(c, d.overriddenMethod());
+        assertNotEquals(d, b.overriddenMethod());
+        assertNotEquals(d, c.overriddenMethod());
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void overrides() {
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/PackageDocImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/PackageDocImplTest.java
new file mode 100644
index 0000000..d056d14
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/PackageDocImplTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.Doc;
+import java.util.Arrays;
+import java.util.Comparator;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class PackageDocImplTest extends BaseTest {
+
+    private PackageDocImpl comExamplePackages;
+
+    @Before
+    public void setUp() {
+        super.setUp();
+        comExamplePackages = PackageDocImpl.create(PACKAGE.comExamplePackages, context);
+    }
+
+    @Ignore("Not used")
+    @Test
+    public void allClasses() {
+    }
+
+    @Ignore("Not used")
+    @Test
+    public void allClasses_filter() {
+    }
+
+    @Test
+    public void ordinaryClasses() {
+        ClassDoc[] ordinaryClasses = comExamplePackages.ordinaryClasses();
+
+        assertEquals(3, ordinaryClasses.length);
+        assertArrayEquals(new String[]{
+                        "ClassWithNested", "ClassWithNested.Nested", "ClassWithNested.Nested.Nested2"},
+                Arrays.stream(ordinaryClasses)
+                        .sorted(Comparator.comparing(Doc::name))
+                        .map(Doc::name)
+                        .toArray(String[]::new)
+        );
+    }
+
+    @Test
+    public void exceptions() {
+        ClassDoc[] exceptions = comExamplePackages.exceptions();
+
+        assertEquals(1, exceptions.length);
+        assertTrue(exceptions[0].isException());
+        assertEquals("Exception", exceptions[0].name());
+    }
+
+    @Test
+    public void errors() {
+        ClassDoc[] errors = comExamplePackages.errors();
+
+        assertEquals(1, errors.length);
+        assertTrue(errors[0].isError());
+        assertEquals("Error", errors[0].name());
+    }
+
+    @Test
+    public void enums() {
+        ClassDoc[] enums = comExamplePackages.enums();
+
+        assertEquals(1, enums.length);
+        assertTrue(enums[0].isEnum());
+        assertEquals("Enum", enums[0].name());
+    }
+
+    @Test
+    public void interfaces() {
+        ClassDoc[] interfaces = comExamplePackages.interfaces();
+
+        assertEquals(1, interfaces.length);
+        assertTrue(interfaces[0].isInterface());
+        assertEquals("Interface", interfaces[0].name());
+    }
+
+    @Test
+    public void annotationTypes() {
+        ClassDoc[] annotationTypes = comExamplePackages.annotationTypes();
+
+        assertEquals(1, annotationTypes.length);
+        assertTrue(annotationTypes[0].isAnnotationType());
+        assertEquals("Annotation", annotationTypes[0].name());
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void annotations() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void findClass() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void isIncluded() {
+    }
+
+    @Test
+    public void name() {
+        assertEquals("com.example.packages", comExamplePackages.name());
+    }
+
+    @Test
+    public void qualifiedName() {
+        assertEquals("com.example.packages", comExamplePackages.qualifiedName());
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/ParamTagImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/ParamTagImplTest.java
new file mode 100644
index 0000000..f66a623
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/ParamTagImplTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.sun.javadoc.ProgramElementDoc;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ParamTagImplTest extends BaseTest {
+
+    // /**
+    //  * @param <T> stored in Box
+    //  */
+    // public static class Box<T> { ... }
+    private ParamTagImpl paramTag_classArg_T_withComment;
+
+    // /**
+    //  * @param storedObject Something valuable
+    //  * @param price
+    //  */
+    // public Box(T storedObject, int price) { ... }
+    private ParamTagImpl paramTag_methodArg_T_withComment;
+    private ParamTagImpl paramTag_methodArg_int_emptyComment;
+
+    @Before
+    public void setUp() {
+        super.setUp();
+
+        ClassDocImpl box = ClassDocImpl.create(GENERIC.box, context);
+        List<ParamTagImpl> tags = getParamTags(box);
+        assertEquals(1, tags.size());
+        paramTag_classArg_T_withComment = tags.get(0);
+
+        ConstructorDocImpl ctor = ConstructorDocImpl.create(CONSTRUCTOR.paramTag_arg2_T_int,
+                context);
+        tags = getParamTags(ctor);
+        assertEquals(2, tags.size());
+        paramTag_methodArg_T_withComment = tags.get(0);
+        paramTag_methodArg_int_emptyComment = tags.get(1);
+    }
+
+    private List<ParamTagImpl> getParamTags(ProgramElementDoc pe) {
+        return Arrays.stream(pe.tags())
+                .filter(tag -> tag instanceof ParamTagImpl)
+                .map(tag -> (ParamTagImpl) tag)
+                .toList();
+    }
+
+    @Test
+    public void parameterName() {
+        assertEquals("T", paramTag_classArg_T_withComment.parameterName());
+        assertEquals("storedObject", paramTag_methodArg_T_withComment.parameterName());
+        assertEquals("price", paramTag_methodArg_int_emptyComment.parameterName());
+    }
+
+    @Test
+    public void parameterComment() {
+        assertEquals("stored in Box", paramTag_classArg_T_withComment.parameterComment());
+        assertEquals("Something valuable", paramTag_methodArg_T_withComment.parameterComment());
+        assertEquals("", paramTag_methodArg_int_emptyComment.parameterComment());
+    }
+
+    @Test
+    public void isTypeParameter() {
+        assertTrue(paramTag_classArg_T_withComment.isTypeParameter());
+        assertFalse(paramTag_methodArg_T_withComment.isTypeParameter());
+        assertFalse(paramTag_methodArg_int_emptyComment.isTypeParameter());
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/ParameterImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/ParameterImplTest.java
new file mode 100644
index 0000000..8deeafd
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/ParameterImplTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import com.google.doclava.javadoc.BaseTest.METHOD.OF_CLASS;
+import com.google.doclava.javadoc.BaseTest.METHOD.PARAMETER;
+import com.sun.javadoc.AnnotatedType;
+import com.sun.javadoc.AnnotationDesc;
+import com.sun.javadoc.Parameter;
+import com.sun.javadoc.Type;
+import java.util.function.BiConsumer;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ParameterImplTest extends BaseTest {
+
+    public static MethodDocImpl arg0;
+    public static MethodDocImpl arg2_int_String;
+    public static MethodDocImpl arg1_annotatedObject; // Annotated with @UniversalAnnotation
+
+    record TestCase(MethodDocImpl method, ExpectedParameter... expectedParameters) {
+
+    }
+
+    private static class ExpectedParameter {
+
+        public final Type type;
+        public final String name;
+        public final AnnotationDesc[] annotations;
+
+        public ExpectedParameter(Type type, String name) {
+            this.type = type;
+            this.name = name;
+            if (type instanceof AnnotatedType ad) {
+                this.annotations = ad.annotations();
+            } else {
+                this.annotations = new AnnotationDesc[0];
+            }
+        }
+    }
+
+    private static TestCase[] TESTS = new TestCase[0];
+
+    @Before
+    public void setUp() {
+        super.setUp();
+        arg0 = MethodDocImpl.create(OF_CLASS.private_int_arg0, context);
+        arg1_annotatedObject = MethodDocImpl.create(OF_CLASS.void_arg1_annotatedObject, context);
+        arg2_int_String =
+                MethodDocImpl.create(OF_CLASS.packagePrivate_String_arg2_int_String, context);
+
+        AnnotatedTypeImpl annotatedObject = (AnnotatedTypeImpl) TypeImpl.create(
+                PARAMETER.Object_annotatedWith_UniversalAnnotation.asType(), context);
+        ClassDocImpl javaLangString = ClassDocImpl.create(INSTANCE.javaLangString, context);
+        // AnnotationDescImpl universalAnnotation =
+        //         new AnnotationDescImpl(annotatedObject.annotations()[0])
+
+        TESTS = new TestCase[]{
+                // "method()" (0 parameters)
+                new TestCase(arg0),
+
+                // "method(@UniversalAnnotation Object obj)" (1 parameter: annotated Object)
+                new TestCase(
+                        arg1_annotatedObject,
+                        new ExpectedParameter(annotatedObject, "obj")
+                ),
+
+                // "method(int a, String b)" (2 parameters: int, String)
+                new TestCase(
+                        arg2_int_String,
+                        new ExpectedParameter(PrimitiveTypeImpl.INT, "a"),
+                        new ExpectedParameter(javaLangString, "b")
+                )
+        };
+    }
+
+    @Test
+    public void type() {
+        testParametersWith((actual, expected) -> assertSame(actual.type(), expected.type));
+    }
+
+    @Test
+    public void name() {
+        testParametersWith((actual, expected) -> assertEquals(actual.name(), expected.name));
+    }
+
+    @Test
+    public void typeName() {
+        testParametersWith((actual, expected) -> {
+            assertEquals(actual.typeName(), ""/*expected.type.qualifiedTypeName()*/);
+        });
+    }
+
+    @Test
+    public void annotations() {
+        testParametersWith((actual, expected) -> {
+            final var actualAnnotations = actual.annotations();
+            final var expectedAnnotations = expected.annotations;
+            assertEquals(expectedAnnotations.length, actualAnnotations.length);
+
+            for (int i = 0; i < expectedAnnotations.length; i++) {
+                var ea = expectedAnnotations[i].annotationType();
+                var aa = actualAnnotations[i].annotationType();
+
+                assertEquals(ea.qualifiedName(), aa.qualifiedName());
+                assertEquals(ea.qualifiedTypeName(), aa.qualifiedTypeName());
+            }
+        });
+    }
+
+    /**
+     * Calls given {@code function} on each pair of <{@code actualParameter}, {@code
+     * expectedParameter}> that are listed in {@link #TESTS}. The {@code function} accepts two
+     * values: actual {@link Parameter} and {@link ExpectedParameter} fixture, and should compare
+     * "actual" value against "expected", throwing an assertion when required.
+     *
+     * Also, asserts that number of actual and expected parameters is same.
+     *
+     * @param function compares actual {@link Parameter} returned from {@link ParameterImpl} with a
+     * fixture.
+     * @throws AssertionError when expectations for actual parameter are not met.
+     */
+    private void testParametersWith(BiConsumer<Parameter, ExpectedParameter> function)
+            throws AssertionError {
+        for (TestCase test : TESTS) {
+            final Parameter[] actualParameters = test.method.parameters();
+            final ExpectedParameter[] expectedParameters = test.expectedParameters;
+            assertEquals(actualParameters.length, expectedParameters.length);
+
+            for (int i = 0; i < expectedParameters.length; i++) {
+                final var actual = actualParameters[i];
+                final var expected = expectedParameters[i];
+
+                function.accept(actual, expected);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/PrimitiveTypeImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/PrimitiveTypeImplTest.java
new file mode 100644
index 0000000..3a35652
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/PrimitiveTypeImplTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static com.google.doclava.javadoc.PrimitiveTypeImpl.BOOLEAN;
+import static com.google.doclava.javadoc.PrimitiveTypeImpl.BYTE;
+import static com.google.doclava.javadoc.PrimitiveTypeImpl.CHAR;
+import static com.google.doclava.javadoc.PrimitiveTypeImpl.DOUBLE;
+import static com.google.doclava.javadoc.PrimitiveTypeImpl.FLOAT;
+import static com.google.doclava.javadoc.PrimitiveTypeImpl.INT;
+import static com.google.doclava.javadoc.PrimitiveTypeImpl.LONG;
+import static com.google.doclava.javadoc.PrimitiveTypeImpl.SHORT;
+import static com.google.doclava.javadoc.PrimitiveTypeImpl.VOID;
+import static com.google.doclava.javadoc.PrimitiveTypeImpl.values;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PrimitiveTypeImplTest extends BaseTest {
+
+    private List<PrimitiveTypeImpl> allPrimitiveTypes;
+
+    @Before
+    public void setUp() {
+        super.setUp();
+        allPrimitiveTypes = Arrays.stream(values()).toList();
+    }
+
+    @Test
+    public void enumValues() {
+        assertEquals(9, PrimitiveTypeImpl.values().length);
+    }
+
+    @Test
+    public void typeName() {
+        assertEquals("boolean", BOOLEAN.typeName());
+        assertEquals("byte", BYTE.typeName());
+        assertEquals("char", CHAR.typeName());
+        assertEquals("double", DOUBLE.typeName());
+        assertEquals("float", FLOAT.typeName());
+        assertEquals("int", INT.typeName());
+        assertEquals("long", LONG.typeName());
+        assertEquals("short", SHORT.typeName());
+        assertEquals("void", VOID.typeName());
+    }
+
+    @Test
+    public void qualifiedTypeName() {
+        assertEquals("boolean", BOOLEAN.qualifiedTypeName());
+        assertEquals("byte", BYTE.qualifiedTypeName());
+        assertEquals("char", CHAR.qualifiedTypeName());
+        assertEquals("double", DOUBLE.qualifiedTypeName());
+        assertEquals("float", FLOAT.qualifiedTypeName());
+        assertEquals("int", INT.qualifiedTypeName());
+        assertEquals("long", LONG.qualifiedTypeName());
+        assertEquals("short", SHORT.qualifiedTypeName());
+        assertEquals("void", VOID.qualifiedTypeName());
+    }
+
+    @Test
+    public void simpleTypeName() {
+        assertEquals("boolean", BOOLEAN.simpleTypeName());
+        assertEquals("byte", BYTE.simpleTypeName());
+        assertEquals("char", CHAR.simpleTypeName());
+        assertEquals("double", DOUBLE.simpleTypeName());
+        assertEquals("float", FLOAT.simpleTypeName());
+        assertEquals("int", INT.simpleTypeName());
+        assertEquals("long", LONG.simpleTypeName());
+        assertEquals("short", SHORT.simpleTypeName());
+        assertEquals("void", VOID.simpleTypeName());
+    }
+
+    @Test
+    public void dimension() {
+        allPrimitiveTypes.forEach(pt -> assertEquals("", pt.dimension()));
+    }
+
+    @Test
+    public void isPrimitive() {
+        allPrimitiveTypes.forEach(pt -> assertTrue(pt.isPrimitive()));
+    }
+
+    @Test
+    public void asClassDoc() {
+        allPrimitiveTypes.forEach(pt -> assertNull(pt.asClassDoc()));
+    }
+
+    @Test
+    public void asParameterizedType() {
+        allPrimitiveTypes.forEach(pt -> assertNull(pt.asParameterizedType()));
+    }
+
+    @Test
+    public void asTypeVariable() {
+        allPrimitiveTypes.forEach(pt -> assertNull(pt.asTypeVariable()));
+    }
+
+    @Test
+    public void asWildcardType() {
+        allPrimitiveTypes.forEach(pt -> assertNull(pt.asWildcardType()));
+    }
+
+    @Test
+    public void asAnnotatedType() {
+        allPrimitiveTypes.forEach(pt -> assertNull(pt.asAnnotatedType()));
+    }
+
+    @Test
+    public void asAnnotationTypeDoc() {
+        allPrimitiveTypes.forEach(pt -> assertNull(pt.asAnnotationTypeDoc()));
+    }
+
+    @Test
+    public void getElementType() {
+        allPrimitiveTypes.forEach(pt -> assertNull(pt.getElementType()));
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/ProgramElementDocImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/ProgramElementDocImplTest.java
new file mode 100644
index 0000000..7063942
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/ProgramElementDocImplTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import com.google.doclava.javadoc.BaseTest.METHOD.OF_INTERFACE;
+import com.sun.javadoc.AnnotationDesc;
+import com.sun.javadoc.AnnotationDesc.ElementValuePair;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ProgramElementDocImplTest extends BaseTest {
+
+    private ClassDocImpl topLevel;
+    private ClassDocImpl nest1;
+    private ClassDocImpl nest2;
+    private MethodDocImpl method_ofInterface;
+    private ConstructorDocImpl ctor;
+    private ClassDocImpl annotatedClass;
+
+    @Before
+    public void setUp() {
+        super.setUp();
+        topLevel = ClassDocImpl.create(CLASS.publicClassWithNests, context);
+        nest1 = ClassDocImpl.create(CLASS.publicClassWithNests$Nest1, context);
+        nest2 = ClassDocImpl.create(CLASS.publicClassWithNests$Nest1$Nest2, context);
+        method_ofInterface = MethodDocImpl.create(OF_INTERFACE.public_void_arg0, context);
+        ctor = ConstructorDocImpl.create(CONSTRUCTOR.empty, context);
+        annotatedClass = ClassDocImpl.create(CLASS.annotatedClass, context);
+    }
+
+    @Test
+    public void containingClass() {
+        assertNull(topLevel.containingClass());
+        assertEquals("PublicClassWithNests", nest1.containingClass().name());
+        assertEquals("PublicClassWithNests.Nest1", nest2.containingClass().name());
+        assertEquals("OfInterface", method_ofInterface.containingClass().name());
+        assertEquals("Constructors", ctor.containingClass().name());
+    }
+
+    @Test
+    public void containingPackage() {
+        assertEquals("classes", topLevel.containingPackage().name());
+        assertEquals("classes", nest1.containingPackage().name());
+        assertEquals("classes", nest2.containingPackage().name());
+        assertEquals("methods", method_ofInterface.containingPackage().name());
+        assertEquals("constructors", ctor.containingPackage().name());
+    }
+
+    @Test
+    public void annotations() {
+        assertAnnotations(topLevel.annotations());
+
+        assertAnnotations(annotatedClass.annotations(),
+                "com.example.classes.UniversalAnnotation",
+                "com.example.classes.AllDefaultAnnotation");
+    }
+
+    private void assertAnnotations(AnnotationDesc[] annotations, String... qualifiedNames) {
+        assertEquals(qualifiedNames.length, annotations.length);
+        for (int i = 0; i < qualifiedNames.length; i++) {
+            final String expectedQualifiedName = qualifiedNames[i];
+            final String actualQualifiedName = annotations[i].annotationType().qualifiedName();
+            assertEquals(expectedQualifiedName, actualQualifiedName);
+        }
+    }
+
+    @Test
+    public void elementValues() {
+        var annotations = annotatedClass.annotations();
+        assertEquals(2, annotations.length);
+
+        // 1. @UniversalAnnotation (with no expectedParameters).
+        var values = annotations[0].elementValues();
+        assertEquals(0, values.length);
+
+        // 2. @AllDefaultAnnotation(str = "abc", integer = 123).
+        values = annotations[1].elementValues();
+        assertEquals(2, values.length);
+        assertElementValues(values[0], "str", "abc");
+        assertElementValues(values[1], "integer", 123);
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T> void assertElementValues(ElementValuePair pair, String expectedDescName,
+            T expectedValue) {
+        var element = pair.element();
+        if (element instanceof AnnotationMethodDocImpl amd) {
+            assertEquals(expectedDescName, amd.name());
+        } else {
+            fail("Expected returned value type of ElementValues.element() to be "
+                    + "AnnotationMethodDocImpl but got " + element.getClass().getSimpleName());
+        }
+
+        // suppressed unchecked cast
+        T value = (T) pair.value().value();
+        assertEquals(expectedValue, value);
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/java/com/google/doclava/javadoc/TagImplTest.java b/doclet_adapter/src/test/java/com/google/doclava/javadoc/TagImplTest.java
new file mode 100644
index 0000000..eeae573
--- /dev/null
+++ b/doclet_adapter/src/test/java/com/google/doclava/javadoc/TagImplTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.google.doclava.javadoc;
+
+import static org.junit.Assert.assertEquals;
+
+import com.sun.javadoc.Tag;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class TagImplTest extends BaseTest {
+
+    private ClassDocImpl various;
+    private Tag author;
+    private Tag version;
+    private Tag see;
+    private Tag since;
+
+    @Before
+    public void setUp() {
+        super.setUp();
+
+        various = ClassDocImpl.create(CLASS.tags$Various, context);
+
+        author = various.tags()[0];
+        version = various.tags()[1];
+        see = various.tags()[2];
+        since = various.tags()[3];
+    }
+
+    @Test
+    public void name() {
+        assertEquals("@author", author.name());
+        assertEquals("@version", version.name());
+        assertEquals("@see", see.name());
+        assertEquals("@since", since.name());
+    }
+
+    @Test
+    public void holder() {
+        assertEquals(various, author.holder());
+        assertEquals(various, see.holder());
+    }
+
+    @Test
+    public void kind() {
+        assertEquals("@author", author.kind());
+        assertEquals("@see", see.kind());
+    }
+
+    @Test
+    public void kind_remapKindHelper() {
+        // Exceptional cases
+        assertEquals("throws", TagImpl.remapKind("exception"));
+        assertEquals("see", TagImpl.remapKind("link"));
+        assertEquals("see", TagImpl.remapKind("linkplain"));
+        assertEquals("serial", TagImpl.remapKind("serialData"));
+
+        // Otherwise, should be an `identity` function
+        assertEquals("see", TagImpl.remapKind("see"));
+        assertEquals("author", TagImpl.remapKind("author"));
+        assertEquals("customTag", TagImpl.remapKind("customTag"));
+    }
+
+    @Test
+    public void text() {
+        assertEquals("@author someone with a very long name", author.text());
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void inlineTags() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void firstSentenceTags() {
+    }
+
+    @Ignore("Not yet implemented")
+    @Test
+    public void position() {
+    }
+}
\ No newline at end of file
diff --git a/doclet_adapter/src/test/resources/sample-project/com/example/classes/AbstractEmptyClass.java b/doclet_adapter/src/test/resources/sample-project/com/example/classes/AbstractEmptyClass.java
new file mode 100644
index 0000000..9f8b811
--- /dev/null
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/AbstractEmptyClass.java
@@ -0,0 +1,4 @@
+package com.example.classes;
+
+public abstract class AbstractEmptyClass {
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/classes/AbstractEmptyInterface.java
similarity index 79%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/classes/AbstractEmptyInterface.java
index c6b98ee..1e4d34b 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/AbstractEmptyInterface.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,7 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.classes;
+
+public abstract interface AbstractEmptyInterface {
+}
diff --git a/doclet_adapter/src/test/resources/sample-project/com/example/classes/AllDefaultAnnotation.java b/doclet_adapter/src/test/resources/sample-project/com/example/classes/AllDefaultAnnotation.java
new file mode 100644
index 0000000..dfef62a
--- /dev/null
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/AllDefaultAnnotation.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.example.classes;
+
+public @interface AllDefaultAnnotation {
+    boolean bool() default true;
+    byte byt() default (byte)1;
+    char ch() default 'a';
+    double dbl() default 3.1d;
+    float flt() default 4.1f;
+    int integer() default 5;
+    long lng() default 6L;
+    short shrt() default (short)7;
+    String str() default "qwe";
+    Class<?> cls() default PublicClass.class;
+    SimpleEnum enm() default SimpleEnum.A;
+    Class<?> annotation() default Override.class; //TODO(nikitai): check this
+    String[] arrayOfStrings() default { "abc", "def", "ghi" };
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/classes/AnnotatedClass.java
similarity index 74%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/classes/AnnotatedClass.java
index c6b98ee..07c450e 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/AnnotatedClass.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,10 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.classes;
+
+@UniversalAnnotation
+@AllDefaultAnnotation(str = "abc", integer = 123)
+public class AnnotatedClass {
+
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/classes/DefaultAnnotation.java
similarity index 81%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/classes/DefaultAnnotation.java
index c6b98ee..1487b37 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/DefaultAnnotation.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,8 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.classes;
+
+@interface DefaultAnnotation {
+
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/classes/DefaultEnum.java
similarity index 83%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/classes/DefaultEnum.java
index c6b98ee..23d1262 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/DefaultEnum.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,7 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.classes;
+
+enum DefaultEnum {
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/classes/ExtendsExternalizable.java
similarity index 74%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/classes/ExtendsExternalizable.java
index c6b98ee..6a81aca 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/ExtendsExternalizable.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,10 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.classes;
+
+import java.io.Externalizable;
+
+public interface ExtendsExternalizable extends Externalizable {
+
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/classes/ExtendsSerializable.java
similarity index 75%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/classes/ExtendsSerializable.java
index c6b98ee..cd73212 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/ExtendsSerializable.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,10 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.classes;
+
+import java.io.Serializable;
+
+public interface ExtendsSerializable extends Serializable {
+
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/classes/FieldsAccessModifiers.java
similarity index 68%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/classes/FieldsAccessModifiers.java
index c6b98ee..11bdaef 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/FieldsAccessModifiers.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,15 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.classes;
+
+public class FieldsAccessModifiers {
+
+    public double public_double;
+
+    private int private_int;
+
+    protected float protected_float;
+
+    long packagePrivate_long;
+}
diff --git a/doclet_adapter/src/test/resources/sample-project/com/example/classes/ImplementsExternalizable.java b/doclet_adapter/src/test/resources/sample-project/com/example/classes/ImplementsExternalizable.java
new file mode 100644
index 0000000..2bd5bcb
--- /dev/null
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/ImplementsExternalizable.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.example.classes;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+public class ImplementsExternalizable implements Externalizable {
+
+    @Override
+    public void writeExternal(ObjectOutput out) throws IOException {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+
+    @Override
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        throw new UnsupportedOperationException("not yet implemented");
+    }
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/classes/ImplementsSerializable.java
similarity index 75%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/classes/ImplementsSerializable.java
index c6b98ee..0b2a9cd 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/ImplementsSerializable.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,9 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.classes;
+
+import java.io.Serializable;
+
+public class ImplementsSerializable implements Serializable {
+}
diff --git a/doclet_adapter/src/test/resources/sample-project/com/example/classes/InnerClasses.java b/doclet_adapter/src/test/resources/sample-project/com/example/classes/InnerClasses.java
new file mode 100644
index 0000000..d6e97f5
--- /dev/null
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/InnerClasses.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.example.classes;
+
+public class InnerClasses {
+    public class PublicNestedClass {}
+    protected class ProtectedNestedClass {}
+    private class PrivateNestedClass {}
+    class NestedClass {}
+
+    public interface PublicNestedInterface {}
+    protected interface ProtectedNestedInterface {}
+    private interface PrivateNestedInterface {}
+    interface NestedInterface {}
+
+    public enum PublicNestedEnum {}
+    protected enum ProtectedNestedEnum {}
+    private enum PrivateNestedEnum {}
+    enum NestedEnum {}
+
+    public @interface PublicNestedAnnotation {}
+    protected @interface ProtectedNestedAnnotation {}
+    private @interface PrivateNestedAnnotation {}
+    @interface NestedAnnotation {}
+}
diff --git a/doclet_adapter/src/test/resources/sample-project/com/example/classes/MethodsAccessModifiers.java b/doclet_adapter/src/test/resources/sample-project/com/example/classes/MethodsAccessModifiers.java
new file mode 100644
index 0000000..e5b9641
--- /dev/null
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/MethodsAccessModifiers.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.example.classes;
+
+import com.example.classes.UniversalAnnotation;
+
+public class MethodsAccessModifiers {
+    public void public_void_arg0() {}
+
+    private int private_int_arg0() {
+        return 0;
+    }
+
+    String packagePrivate_String_arg2_int_String(int a, String b) {
+        return a + b;
+    }
+
+    protected void protected_void_arg0() {}
+}
+
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/classes/PackagePrivateClass.java
similarity index 82%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/classes/PackagePrivateClass.java
index c6b98ee..13cbbf9 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/PackagePrivateClass.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,7 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.classes;
+
+class PackagePrivateClass {
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/classes/ParametrizedAnnotation.java
similarity index 64%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/classes/ParametrizedAnnotation.java
index c6b98ee..813ad01 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/ParametrizedAnnotation.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,12 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.classes;
+
+public @interface ParametrizedAnnotation {
+    int primitiveI();
+    long primitiveDefaultL() default 5L;
+    String stringParametrized();
+    String stringDefault() default "N/A";
+    String[] arrayOfStrings();
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/classes/PublicAnnotation.java
similarity index 81%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/classes/PublicAnnotation.java
index c6b98ee..bc585bd 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/PublicAnnotation.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,7 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.classes;
+
+public @interface PublicAnnotation {
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/classes/PublicClass.java
similarity index 82%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/classes/PublicClass.java
index c6b98ee..cba3303 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/PublicClass.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,7 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.classes;
+
+public class PublicClass {
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/classes/PublicClassWithNests.java
similarity index 69%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/classes/PublicClassWithNests.java
index c6b98ee..40a16c8 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/PublicClassWithNests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,13 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.classes;
+
+public class PublicClassWithNests {
+    public class Nest1 {
+        public class Nest2 {
+            public class Nest3 {
+            }
+        }
+    }
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/classes/PublicEnum.java
similarity index 82%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/classes/PublicEnum.java
index c6b98ee..11d2f2b 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/PublicEnum.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,8 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.classes;
+
+public enum PublicEnum {
+
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/classes/PublicInterface.java
similarity index 81%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/classes/PublicInterface.java
index c6b98ee..7f04ebe 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/PublicInterface.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,7 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.classes;
+
+public interface PublicInterface {
+}
diff --git a/doclet_adapter/src/test/resources/sample-project/com/example/classes/SimpleEnum.java b/doclet_adapter/src/test/resources/sample-project/com/example/classes/SimpleEnum.java
new file mode 100644
index 0000000..34df999
--- /dev/null
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/SimpleEnum.java
@@ -0,0 +1,5 @@
+package com.example.classes;
+
+public enum SimpleEnum {
+    A, B, C
+}
diff --git a/doclet_adapter/src/test/resources/sample-project/com/example/classes/Tags.java b/doclet_adapter/src/test/resources/sample-project/com/example/classes/Tags.java
new file mode 100644
index 0000000..1b509b8
--- /dev/null
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/Tags.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.example.classes;
+
+public class Tags {
+
+    /**
+     * @see PublicClass
+     * @see PublicAnnotation with comments
+     * @see <a href="https://example.com">html link</a>
+     */
+    public static class See {
+
+    }
+
+    /**
+     * @throws IllegalArgumentException
+     * @throws IllegalArgumentException with some comments
+     */
+    public static class Throws {
+
+    }
+
+    /**
+     * First sentence of the class that consists of three tags: text, inline ({@code something})
+     * and text. Then goes the second sentence of class javadoc. It is followed by a third
+     * sentence that has some inline tags, such as {@code some code},
+     * {@link java.lang.Integer label} and {@linkplain java.lang.Byte label}.
+     *
+     * @author someone with a very long name
+     * @version version
+     * @see Throws
+     * @since 1.0
+     */
+    public static class Various {
+
+        /**
+         * @serial field description
+         * @see #method(String) for details
+         */
+        private int serial;
+
+        /**
+         * First sentence of method javadoc. Then goes the second sentence which contains some
+         * inline tags, such as {@code code block} and {@link #serial label}.
+         *
+         * @exception IllegalArgumentException iae desc
+         * @throws NullPointerException npe desc
+         * @param x description of param named x
+         * @return number, always zero
+         * @see Integer
+         * @since 1.1
+         */
+        public Integer method(String x) throws Exception {
+            return 0;
+        }
+
+        /**
+         * This method is marked as deprecated in javadoc with a tag.
+         *
+         * @deprecated
+         */
+        public void deprecatedMethod() {
+
+        }
+
+    }
+
+    /**
+     * Fixture to test {@link com.google.doclava.javadoc.ParamTagImpl}.
+     *
+     * @param <T> stored in Box
+     */
+    public static class Box<T> {
+        private T storedObject;
+        private int price;
+
+        private Box() {}
+
+        /**
+         * @param storedObject Something valuable
+         * @param price
+         */
+        public Box(T storedObject, int price) {
+            this.storedObject = storedObject;
+            this.price = price;
+        }
+
+        public T value() {
+            return storedObject;
+        }
+    }
+
+    /**
+     * @see
+     */
+    public class Malformed {
+
+    }
+}
diff --git a/doclet_adapter/src/test/resources/sample-project/com/example/classes/UniversalAnnotation.java b/doclet_adapter/src/test/resources/sample-project/com/example/classes/UniversalAnnotation.java
new file mode 100644
index 0000000..70dc908
--- /dev/null
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/classes/UniversalAnnotation.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.example.classes;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation that can annotate anything (all possible targets), used in tests.
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.ANNOTATION_TYPE,
+        ElementType.CONSTRUCTOR,
+        ElementType.FIELD,
+        ElementType.LOCAL_VARIABLE,
+        ElementType.METHOD,
+        ElementType.MODULE,
+        ElementType.PACKAGE,
+        ElementType.PARAMETER,
+        ElementType.RECORD_COMPONENT,
+        ElementType.TYPE,
+        ElementType.TYPE_PARAMETER,
+        ElementType.TYPE_USE})
+public @interface UniversalAnnotation {
+
+}
diff --git a/doclet_adapter/src/test/resources/sample-project/com/example/constructors/Constructors.java b/doclet_adapter/src/test/resources/sample-project/com/example/constructors/Constructors.java
new file mode 100644
index 0000000..a17e354
--- /dev/null
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/constructors/Constructors.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.example.constructors;
+
+public class Constructors {
+
+    private int a;
+    private String b;
+
+    private Constructors() {
+
+    }
+
+    protected Constructors(int a) {
+        this.a = a;
+    }
+
+    public Constructors(String b) {
+        this.b = b;
+    }
+
+    Constructors(int a, String b) {
+        this.a = a;
+        this.b = b;
+    }
+}
diff --git a/doclet_adapter/src/test/resources/sample-project/com/example/fields/Arrays.java b/doclet_adapter/src/test/resources/sample-project/com/example/fields/Arrays.java
new file mode 100644
index 0000000..aba4bd4
--- /dev/null
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/fields/Arrays.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.example.fields;
+
+import java.util.List;
+
+public class Arrays<T> {
+
+    public int[] arr_int_1;
+
+    // ClassDoc
+    public String[][] arr_String_2;
+
+    // TypeVariable
+    public T[][][] arr_T_3;
+
+    // Parameterized type
+    public List<String>[][][][] arr_ListOfString_4;
+
+    // Annotation type
+    public Override[][][][][] arr_Override_5;
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/fields/Fields.java
similarity index 64%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/fields/Fields.java
index c6b98ee..07fee31 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/fields/Fields.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,15 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.fields;
+
+public class Fields {
+
+    public int public_int;
+
+    public transient volatile Object public_transient_volatile_Object;
+
+    public final int public_final_int = 5;
+
+    public final String public_final_String = "abc";
+}
diff --git a/doclet_adapter/src/test/resources/sample-project/com/example/methods/OfClass.java b/doclet_adapter/src/test/resources/sample-project/com/example/methods/OfClass.java
new file mode 100644
index 0000000..9d50b48
--- /dev/null
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/methods/OfClass.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * 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.
+ */
+
+package com.example.methods;
+
+import com.example.classes.UniversalAnnotation;
+
+public abstract class OfClass {
+    public void public_void_arg0() {}
+
+    private int private_int_arg0() {
+        return 0;
+    }
+
+    String packagePrivate_String_arg2_int_String(int a, String b) {
+        return a + b;
+    }
+
+    public abstract void public_abstract_void_arg0();
+
+    @Override
+    public String toString() {
+        return super.toString();
+    }
+
+    Object void_arg1_annotatedObject(@UniversalAnnotation Object obj) {}
+}
+
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/methods/OfInterface.java
similarity index 70%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/methods/OfInterface.java
index c6b98ee..4a51863 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/methods/OfInterface.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,12 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.methods;
+
+public interface OfInterface {
+    void public_void_arg0();
+
+    default String public_default_String_arg0() {
+        return "string";
+    }
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/methods/override/A.java
similarity index 76%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/methods/override/A.java
index c6b98ee..55e1081 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/methods/override/A.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,11 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.methods.override;
+
+public class A {
+
+    public String name() {
+        return "A";
+    }
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/methods/override/B.java
similarity index 74%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/methods/override/B.java
index c6b98ee..637fc19 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/methods/override/B.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,12 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.methods.override;
+
+public class B extends A {
+
+    @Override
+    public String name() {
+        return "B";
+    }
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/methods/override/C.java
similarity index 74%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/methods/override/C.java
index c6b98ee..7e3b426 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/methods/override/C.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,12 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.methods.override;
+
+public class C extends B {
+
+    @Override
+    public String name() {
+        return "C";
+    }
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/methods/override/D.java
similarity index 74%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/methods/override/D.java
index c6b98ee..6460fca 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/methods/override/D.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,12 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.methods.override;
+
+public class D extends A {
+
+    @Override
+    public String name() {
+        return "D";
+    }
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/methods/override/package-info.java
similarity index 65%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/methods/override/package-info.java
index c6b98ee..67995b3 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/methods/override/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,18 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+/**
+ * Test fixtures for testing {@link com.google.doclava.javadoc.MethodDocImpl#overriddenMethod()}.
+ * The hierarchy is the following:
+ *
+ * <pre>
+ * A <- D
+ * ^
+ * |
+ * B
+ * ^
+ * |
+ * C
+ * </pre>
+ */
+package com.example.methods.override;
\ No newline at end of file
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/packages/Annotation.java
similarity index 81%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/packages/Annotation.java
index c6b98ee..918bdea 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/packages/Annotation.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,8 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.packages;
+
+public @interface Annotation {
+
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/packages/ClassWithNested.java
similarity index 72%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/packages/ClassWithNested.java
index c6b98ee..03a5fa7 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/packages/ClassWithNested.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,12 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.packages;
+
+public class ClassWithNested {
+    public static class Nested {
+        public static class Nested2 {
+
+        }
+    }
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/packages/Enum.java
similarity index 83%
rename from settings.gradle
rename to doclet_adapter/src/test/resources/sample-project/com/example/packages/Enum.java
index c6b98ee..cd9400f 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/packages/Enum.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,7 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.packages;
+
+public enum Enum {
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/packages/Error.java
similarity index 80%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/packages/Error.java
index c6b98ee..e17b0d1 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/packages/Error.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,8 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.packages;
+
+public class Error extends java.lang.Error {
+
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/packages/Exception.java
similarity index 79%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/packages/Exception.java
index c6b98ee..fb77099 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/packages/Exception.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,8 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.packages;
+
+public class Exception extends java.lang.Exception {
+
+}
diff --git a/settings.gradle b/doclet_adapter/src/test/resources/sample-project/com/example/packages/Interface.java
similarity index 82%
copy from settings.gradle
copy to doclet_adapter/src/test/resources/sample-project/com/example/packages/Interface.java
index c6b98ee..78834e4 100644
--- a/settings.gradle
+++ b/doclet_adapter/src/test/resources/sample-project/com/example/packages/Interface.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,8 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+package com.example.packages;
+
+public interface Interface {
+
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..0e85f4b
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,2 @@
+kotlin.code.style=official
+org.gradle.parallel=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 13372ae..249e583 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 27a6e95..daab1a1 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Aug 16 10:43:36 PDT 2016
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=../../../../tools/external/gradle/gradle-7.4-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
+distributionSha256Sum=db9c8211ed63f61f60292c69e80d89196f9eb36665e369e7f00ac4cc841c2219
\ No newline at end of file
diff --git a/gradlew b/gradlew
index 89509d7..17c1492 100755
--- a/gradlew
+++ b/gradlew
@@ -1,79 +1,129 @@
 #!/usr/bin/env bash
 
+#
+# Copyright © 2015-2021 the original authors.
+#
+# 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
+#
+#      https://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.
+#
+
 ##############################################################################
-##
-##  Gradle start up script for UN*X
-##
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
 ##############################################################################
 
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
+done
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
 
 APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+APP_BASE_NAME=${0##*/}
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 
 # Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
 
-warn ( ) {
+warn () {
     echo "$*"
-}
+} >&2
 
-die ( ) {
+die () {
     echo
     echo "$*"
     echo
     exit 1
-}
+} >&2
 
 # OS specific support (must be 'true' or 'false').
 cygwin=false
 msys=false
 darwin=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MINGW* )
-    msys=true
-    ;;
+nonstop=false
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
 esac
 
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
-    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
-APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
-
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 
+
 # Determine the Java command to use to start the JVM.
 if [ -n "$JAVA_HOME" ] ; then
     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
         # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
+        JAVACMD=$JAVA_HOME/jre/sh/java
     else
-        JAVACMD="$JAVA_HOME/bin/java"
+        JAVACMD=$JAVA_HOME/bin/java
     fi
     if [ ! -x "$JAVACMD" ] ; then
         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -82,7 +132,7 @@
 location of your Java installation."
     fi
 else
-    JAVACMD="java"
+    JAVACMD=java
     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 
 Please set the JAVA_HOME variable in your environment to match the
@@ -90,85 +140,101 @@
 fi
 
 # Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
-    # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
-        fi
-        i=$((i+1))
-    done
-    case $i in
-        (0) set -- ;;
-        (1) set -- "$args0" ;;
-        (2) set -- "$args0" "$args1" ;;
-        (3) set -- "$args0" "$args1" "$args2" ;;
-        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
-        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
-        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
     esac
 fi
 
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
-    JVM_OPTS=("$@")
-}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
 
-# Change the project's .gradle to the android out dir.
-ANDROID_GRADLE_ROOT="$APP_HOME/../../out/host/gradle/frameworks/support"
-if [[ -z "$ANDROID_CACHE_DIR" ]]; then
-  ANDROID_CACHE_DIR="$ANDROID_GRADLE_ROOT/.gradle"
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
+        fi
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
+    done
 fi
 
-# Change the local user directories to be under the android out dir
-export GRADLE_USER_HOME="$ANDROID_GRADLE_ROOT/.gradle"
-export M2_HOME="$ANDROID_GRADLE_ROOT/.m2"
+# Collect all arguments for the java command;
+#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+#     shell script including quotes and variable substitutions, so put them in
+#     double quotes to make sure that they get re-expanded; and
+#   * put everything else in single quotes, so that it's not re-expanded.
 
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain --project-cache-dir=$ANDROID_CACHE_DIR "$@"
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+    die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..f127cfd
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,91 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/print-progress.sh b/print-progress.sh
new file mode 100755
index 0000000..0bab6e8
--- /dev/null
+++ b/print-progress.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+
+impl_path="doclet_adapter/src/main/java/com/google/doclava/javadoc"
+
+used_total=$(printf '%d' $(grep -ri '@Used' $impl_path | wc -l))
+used_implemented=$(printf '%d' $(grep -ri '@Used(implemented = true)' | wc -l))
+unused_total=$(printf '%d' $(grep -ri '@Unused' $impl_path | wc -l))
+unused_implemented=$(printf '%d' $(grep -ri '@Unused(implemented = true)' $impl_path | wc -l))
+
+total=$(($used_total + $unused_total))
+total_implemented=$(($used_implemented + $unused_implemented))
+perc_impl_of_used=$(bc <<< "scale=2; $used_implemented * 100 / $used_total")
+perc_impl_of_unused=$(bc <<< "scale=2; $unused_implemented * 100 / $unused_total")
+perc_impl_of_all=$(bc <<< "scale=2; ($used_implemented + $unused_implemented) * 100 / $total")
+
+echo "Current progress: ${perc_impl_of_used}%
+
+== Methods in implementation classes ==
+Total (used+unused)
+    total:       ${total} methods
+    implemented: ${total_implemented}/${total} (${perc_impl_of_all}%)
+Used
+    total:       ${used_total}
+    implemented: ${used_implemented}/${used_total} (${perc_impl_of_used}%)
+Unused
+    total:       ${unused_total}
+    implemented: ${unused_implemented}/${unused_total} (${perc_impl_of_unused}%)
+"
diff --git a/res/assets/templates/macros.cs b/res/assets/templates/macros.cs
index db502bb..f883596 100644
--- a/res/assets/templates/macros.cs
+++ b/res/assets/templates/macros.cs
@@ -273,10 +273,14 @@
       else
         ?><a href="<?cs var:toroot ?>guide/topics/manifest/uses-sdk-element.html#ApiLevels">API level<?cs
       /if ?> <?cs
-    var:obj.since ?></a><?cs
+    var:obj.since ?></a><?cs if:obj.sdkextsince ?><br/>Also in <a href="<?cs var:toroot ?>sdkExtensions"><?cs var:obj.sdkextsince ?></a><?cs /if ?><?cs
   else ?><a data-version-added="<?cs var:obj.since ?>" href="<?cs var:toroot ?>preview/"><b>Added in Android <?cs
-    var:obj.since ?></b></a><?cs
+    var:obj.since ?></b></a><?cs if:obj.sdkextsince ?><br/>Also in <a href="<?cs var:toroot ?>sdkExtensions"><?cs var:obj.sdkextsince ?></a><?cs /if ?><?cs
   /if?><?cs
+elif:obj.sdkextsince ?>
+  <?cs # This symbol exists in an extension SDK, but not in a finalized dessert ?>
+  Added in <a href="<?cs var:toroot ?>sdkExtensions"><?cs var:obj.sdkextsince ?></a>
+<?cs
 /if ?>
   <?cs if:obj.deprecatedsince ?><?cs
     if:class.artifact ?><br>Deprecated in version <?cs var:obj.deprecatedsince ?><?cs
diff --git a/settings.gradle b/settings.gradle.kts
similarity index 65%
copy from settings.gradle
copy to settings.gradle.kts
index c6b98ee..8e4906d 100644
--- a/settings.gradle
+++ b/settings.gradle.kts
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,4 +14,10 @@
  * limitations under the License.
  */
 
-rootProject.name = 'doclava'
\ No newline at end of file
+rootProject.name = "doclava"
+
+// Gradle launched from IntelliJ IDEA?
+val ideaActive = System.getProperty("idea.active").toBoolean()
+
+// Uses a custom implementation of com.sun.javadoc using jdk.javadoc.doclet API.
+include("doclet_adapter")
diff --git a/src/com/google/doclava/ClassInfo.java b/src/com/google/doclava/ClassInfo.java
index 2a5db75..e0ee7d0 100644
--- a/src/com/google/doclava/ClassInfo.java
+++ b/src/com/google/doclava/ClassInfo.java
@@ -1255,6 +1255,7 @@
     TagInfo.makeHDF(data, base + ".shortDescr", this.firstSentenceTags());
     TagInfo.makeHDF(data, base + ".deprecated", deprecatedTags());
     data.setValue(base + ".since", getSince());
+    data.setValue(base + ".sdkextsince", getSdkExtSince());
     if (isDeprecated()) {
       data.setValue(base + ".deprecatedsince", getDeprecatedSince());
     }
@@ -1326,6 +1327,7 @@
       data.setValue("class.kind", kind);
     }
     data.setValue("class.since", getSince());
+    data.setValue("class.sdkextsince", getSdkExtSince());
     if (isDeprecated()) {
       data.setValue("class.deprecatedsince", getDeprecatedSince());
     }
diff --git a/src/com/google/doclava/Comment.java b/src/com/google/doclava/Comment.java
index 29154c2..9c2a392 100644
--- a/src/com/google/doclava/Comment.java
+++ b/src/com/google/doclava/Comment.java
@@ -35,6 +35,8 @@
           "@since",
           //value is an Android API level (set automatically by metalava)
           "@apiSince",
+          // value is "<Android SDK extension> <api-level>" (set automatically by metalava)
+          "@sdkExtSince",
           "@deprecated",
           //value is an Android API level (set automatically by metalava)
           "@deprecatedSince",
@@ -333,6 +335,11 @@
       mParamTagsList.add(new ParamTagInfo("@param", "@param", text, mBase, pos));
     } else if (name.equals("@apiSince")) {
       setApiSince(text);
+    } else if (name.equals("@sdkExtSince")) {
+      if (getSdkExtSince() != null) {
+        Errors.error(Errors.MULTIPLE_SDK_EXT_INFO, pos, "API symbol has multiple @sdkExtSince javadoc comments");
+      }
+      setSdkExtSince(text);
     } else if (name.equals("@deprecatedSince")) {
       setDeprecatedSince(text);
     } else if (name.equals("@see")) {
@@ -562,6 +569,17 @@
     return mApiSince;
   }
 
+  public void setSdkExtSince(String sdkextsince) {
+    if (sdkextsince != null) {
+      sdkextsince = sdkextsince.trim();
+    }
+    mSdkExtSince = sdkextsince;
+  }
+
+  public String getSdkExtSince() {
+    return mSdkExtSince;
+  }
+
   public boolean isDocOnly() {
     if (mDocOnly == null) {
       mDocOnly = (mText != null) && (mText.indexOf("@doconly") >= 0);
@@ -639,6 +657,7 @@
   Boolean mDeprecated = null;
   String mDeprecatedSince;
   String mApiSince;
+  String mSdkExtSince;
   String mText;
   ContainerInfo mBase;
   SourcePositionInfo mPosition;
diff --git a/src/com/google/doclava/DocInfo.java b/src/com/google/doclava/DocInfo.java
index fae225f..8fa577f 100644
--- a/src/com/google/doclava/DocInfo.java
+++ b/src/com/google/doclava/DocInfo.java
@@ -107,6 +107,17 @@
     return mSince;
   }
 
+  public void setSdkExtSince(String sdkextsince) {
+    mSdkExtSince = sdkextsince;
+  }
+
+  public String getSdkExtSince() {
+    if (Doclava.METALAVA_API_SINCE) {
+      mSdkExtSince = comment().getSdkExtSince();
+    }
+    return mSdkExtSince;
+  }
+
   /**
    * Sets the artifact in which the class resides.
    * <p>
@@ -168,6 +179,7 @@
   Comment mComment;
   SourcePositionInfo mPosition;
   private String mSince;
+  private String mSdkExtSince;
   private String mArtifact;
   private String mDeprecatedSince;
   private Set<FederatedSite> mFederatedReferences = new LinkedHashSet<FederatedSite>();
diff --git a/src/com/google/doclava/Doclava.java b/src/com/google/doclava/Doclava.java
index 45804a1..e164faa 100644
--- a/src/com/google/doclava/Doclava.java
+++ b/src/com/google/doclava/Doclava.java
@@ -22,24 +22,55 @@
 import com.google.clearsilver.jsilver.resourceloader.CompositeResourceLoader;
 import com.google.clearsilver.jsilver.resourceloader.FileSystemResourceLoader;
 import com.google.clearsilver.jsilver.resourceloader.ResourceLoader;
-
-import com.sun.javadoc.*;
-
-import java.util.*;
-import java.util.jar.JarFile;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.io.*;
-import java.lang.reflect.Proxy;
+import com.google.doclava.javadoc.RootDocImpl;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.Doc;
+import com.sun.javadoc.MemberDoc;
+import com.sun.javadoc.RootDoc;
+import com.sun.javadoc.Type;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintStream;
 import java.lang.reflect.Array;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.jar.JarFile;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import javax.lang.model.SourceVersion;
+import jdk.javadoc.doclet.Doclet;
+import jdk.javadoc.doclet.DocletEnvironment;
+import jdk.javadoc.doclet.Reporter;
 
-public class Doclava {
+public class Doclava implements Doclet {
+
   private static final String SDK_CONSTANT_ANNOTATION = "android.annotation.SdkConstant";
   private static final String SDK_CONSTANT_TYPE_ACTIVITY_ACTION =
       "android.annotation.SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION";
@@ -139,9 +170,1353 @@
   private static boolean samplesRef = false;
   private static boolean sac = false;
 
-  public static boolean checkLevel(int level) {
-    return (showLevel & level) == level;
-  }
+    private static ArrayList<String> knownTagsFiles = new ArrayList<>();
+    private static String keepListFile;
+    private static String proguardFile;
+    private static String proofreadFile;
+    private static String todoFile;
+    private static String stubsDir;
+    private static HashSet<String> stubPackages;
+    private static HashSet<String> stubImportPackages;
+    private static boolean stubSourceOnly;
+    private static boolean keepStubComments;
+    private static String sdkValuePath;
+    private static String apiFile;
+    private static String dexApiFile;
+    private static String removedApiFile;
+    private static String removedDexApiFile;
+    private static String exactApiFile;
+    private static String privateApiFile;
+    private static String privateDexApiFile;
+    private static String apiMappingFile;
+    private static boolean offlineMode;
+
+    @Override
+    public void init(Locale locale, Reporter reporter) {
+        keepListFile = null;
+        proguardFile = null;
+        proofreadFile = null;
+        todoFile = null;
+        sdkValuePath = null;
+        stubsDir = null;
+        // Create the dependency graph for the stubs  directory
+        offlineMode = false;
+        apiFile = null;
+        dexApiFile = null;
+        removedApiFile = null;
+        removedDexApiFile = null;
+        exactApiFile = null;
+        privateApiFile = null;
+        privateDexApiFile = null;
+        apiMappingFile = null;
+        stubPackages = null;
+        stubImportPackages = null;
+        stubSourceOnly = false;
+        keepStubComments = false;
+    }
+
+    @Override
+    public String getName() {
+        return "Doclava";
+    }
+
+    /**
+     * @implNote
+     * {@code -overview} option used to be a built-in parameter in javadoc
+     * tool, and with new Doclet APIs it was moved to
+     * {@link jdk.javadoc.doclet.StandardDoclet}, so we have to implement this
+     * functionality by ourselves.
+     */
+    @Override
+    public Set<? extends Option> getSupportedOptions() {
+        Set<Doclet.Option> options = new HashSet<>();
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-overview");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() {
+                        return "Pick overview documentation from HTML file";
+                    }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<file>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        // TODO(nikitai): implement "overview" file inclusion.
+                        //  This used to be built in javadoc tool but in new Doclet APIs it was
+                        //  removed from default functionality and moved to StandardDoclet
+                        //  implementation. In our case we need to implement this on our own.
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-d");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() {
+                        return "Destination directory for output files";
+                    }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<directory>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        outputPathBase = outputPathHtmlDirs = ClearPage.outputDir
+                                = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-templatedir");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() {
+                        return "Templates for jSilver template engine used to generate docs";
+                    }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<directory>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        ClearPage.addTemplateDir(arguments.get(0));
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-hdf");
+                    @Override public int          getArgumentCount() { return 2; }
+                    @Override public String       getDescription() {
+                        return """
+                                Doclava uses the jSilver template engine to render docs. This
+                                option adds a key-value pair to the global data holder object which
+                                is passed to all render calls. Think of it as a list of default
+                                parameters for jSilver.""";
+                    }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<key> <value>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        mHDFData.add(new String[] { arguments.get(0), arguments.get(1) });
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-knowntags");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() {
+                        return """
+                                List of non-standard tags used in sources.
+                                Example: ${ANDROID_BUILD_TOP}/libcore/known_oj_tags.txt""";
+                    }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<file>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        knownTagsFiles.add(arguments.get(0));
+                        return true; }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-apidocsdir");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() {
+                        return """
+                                Javadoc output directory path relative to root, which is specified \
+                                with '-d root'
+                                
+                                Default value: 'reference/'""";
+                    }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<path>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        javadocDir = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-toroot");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() {
+                        return """
+                                Relative path to documentation root.
+                                If set, use <path> as a (relative or absolute) link to \
+                                documentation root in .html pages.
+                                
+                                If not set, an auto-generated path traversal links will be used, \
+                                e.g. “../../../”.
+                                """;
+                    }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<path>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        ClearPage.toroot = arguments.get(0);
+                        return true; }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-samplecode");
+                    @Override public int          getArgumentCount() { return 3; }
+                    @Override public String       getDescription() {
+                        return """
+                                Adds a browsable sample code project from <source> directory under \
+                                <dest> path relative to root (specified with '-d' <directory>) and \
+                                named <title>.
+                                """;
+                    }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() {
+                        return "<source> <dest> <title>";
+                    }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        sampleCodes.add(new SampleCode(arguments.get(0), arguments.get(1), arguments.get(2)));
+                        samplesRef = true;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-samplegroup");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() {
+                        return "Add a sample code project group";
+                    }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<group>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        sampleCodeGroups.add(new SampleCode(null, null, arguments.get(0)));
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-samplesdir");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() {
+                        return """
+                                Directory where to look for samples. Android uses \
+                                ${ANDROID_BUILD_TOP}/development/samples/browseable.
+                                """;
+                    }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<directory>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        samplesRef = true;
+                        getSampleProjects(new File(arguments.get(0)));
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-htmldir");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<path>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        inputPathHtmlDirs.add(arguments.get(0));
+                        ClearPage.htmlDirs = inputPathHtmlDirs;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-htmldir2");
+                    @Override public int          getArgumentCount() { return 2; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() {
+                        return "<input_path> <output_path>";
+                    }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        if (arguments.get(1).equals("default")) {
+                            inputPathHtmlDir2.add(arguments.get(0));
+                        } else {
+                            inputPathHtmlDir2.add(arguments.get(0));
+                            outputPathHtmlDir2 = arguments.get(1);
+                        }
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-resourcesdir");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<path>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        inputPathResourcesDir = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-resourcesoutdir");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<path>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        outputPathResourcesDir = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-title");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<title>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        Doclava.title = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-werror");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        // b/270335911: disable warnings as errors until new findings are addressed.
+                        // Errors.setWarningsAreErrors(true);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-lerror");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        // b/270335653: disable lint warnings as errors until new findings are addressed.
+                        // Errors.setLintsAreErrors(true);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-error");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<code_value>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        try {
+                            int level = Integer.parseInt(arguments.get(0));
+                            Errors.setErrorLevel(level, Errors.ERROR);
+                            return true;
+                        } catch (NumberFormatException e) {
+                            return false;
+                        }
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-warning");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<code_value>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        try {
+                            int level = Integer.parseInt(arguments.get(0));
+                            Errors.setErrorLevel(level, Errors.WARNING);
+                            return true;
+                        } catch (NumberFormatException e) {
+                            return false;
+                        }
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-lint");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<code_value>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        try {
+                            int level = Integer.parseInt(arguments.get(0));
+                            Errors.setErrorLevel(level, Errors.LINT);
+                            return true;
+                        } catch (NumberFormatException e) {
+                            return false;
+                        }
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-hide");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<code_value>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        try {
+                            int level = Integer.parseInt(arguments.get(0));
+                            Errors.setErrorLevel(level, Errors.HIDDEN);
+                            return true;
+                        } catch (NumberFormatException e) {
+                            return false;
+                        }
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-keeplist");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<list>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        keepListFile = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-showUnannotated");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        showUnannotated = true;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-showAnnotation");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<annotation>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        showAnnotations.add(arguments.get(0));
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-hideAnnotation");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<annotation>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        hideAnnotations.add(arguments.get(0));
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-showAnnotationOverridesVisibility");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        showAnnotationOverridesVisibility = true;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-hidePackage");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<package>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        hiddenPackages.add(arguments.get(0));
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-proguard");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<arg>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        proguardFile = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-proofread");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<arg>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        proofreadFile = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-todo");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<file>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        todoFile = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-public");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        showLevel = SHOW_PUBLIC;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-protected");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        showLevel = SHOW_PROTECTED;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-package");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        showLevel = SHOW_PACKAGE;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-private");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        showLevel = SHOW_PRIVATE;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-hidden");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        showLevel = SHOW_HIDDEN;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-stubs");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<stubs>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        stubsDir = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-stubpackages");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<packages>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        stubPackages = new HashSet<>();
+                        stubPackages.addAll(Arrays.asList(arguments.get(0).split(":")));
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-stubimportpackages");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<packages>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        stubImportPackages = new HashSet<>();
+                        for (String pkg : arguments.get(0).split(":")) {
+                            stubImportPackages.add(pkg);
+                            hiddenPackages.add(pkg);
+                        }
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-stubsourceonly");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        stubSourceOnly = true;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-keepstubcomments");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        keepStubComments = true;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-sdkvalues");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<path>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        sdkValuePath = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-api");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<file>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        apiFile = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-dexApi");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<file>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        dexApiFile = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-removedApi");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<file>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        removedApiFile = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-removedDexApi");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<file>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        removedDexApiFile = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-exactApi");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<file>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        exactApiFile = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-privateApi");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<file>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        privateApiFile = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-privateDexApi");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<file>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        privateDexApiFile = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-apiMapping");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<file>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        apiMappingFile = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-nodocs");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        generateDocs = false;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-noassets");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        includeAssets = false;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-nodefaultassets");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        includeDefaultAssets = false;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-parsecomments");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        parseComments = true;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-metalavaApiSince");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        METALAVA_API_SINCE = true;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-since");
+                    @Override public int          getArgumentCount() { return 2; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<major> <minor>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        sinceTagger.addVersion(arguments.get(0), arguments.get(1));
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-artifact");
+                    @Override public int          getArgumentCount() { return 2; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<arg1> <arg2>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        artifactTagger.addArtifact(arguments.get(0), arguments.get(1));
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-offlinemode");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        // TODO(nikitai): This option is not used anywhere, consider removing.
+                        offlineMode = true;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-metadataDebug");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        META_DBG = true;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-includePreview");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        INCLUDE_PREVIEW = true;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-ignoreJdLinks");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        if (DEVSITE_STATIC_ONLY) {
+                            DEVSITE_IGNORE_JDLINKS = true;
+                        }
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-federate");
+                    @Override public int          getArgumentCount() { return 2; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<name> <URL>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        try {
+                            String name = arguments.get(0);
+                            URL federationURL = new URL(arguments.get(1));
+                            federationTagger.addSiteUrl(name, federationURL);
+                        } catch (MalformedURLException e) {
+                            System.err.println("Could not parse URL for federation: " + arguments.get(0));
+                            return false;
+                        }
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-federationapi");
+                    @Override public int          getArgumentCount() { return 2; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<name> <file>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        String name = arguments.get(0);
+                        String file = arguments.get(1);
+                        federationTagger.addSiteApi(name, file);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-gmsref");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        gmsRef = true;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-gcmref");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        gcmRef = true;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-yaml");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<file>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        yamlNavFile = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-dac_libraryroot");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<library_root>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        libraryRoot = ensureSlash(arguments.get(0));
+                        mHDFData.add(new String[] {"library.root", arguments.get(0)});
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-dac_dataname");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<data_name>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        mHDFData.add(new String[] {"dac_dataname", arguments.get(0)});
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-documentannotations");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<path>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        documentAnnotations = true;
+                        documentAnnotationsPath = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-referenceonly");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        referenceOnly = true;
+                        mHDFData.add(new String[] {"referenceonly", "1"});
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-staticonly");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        staticOnly = true;
+                        mHDFData.add(new String[] {"staticonly", "1"});
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-navtreeonly");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        NAVTREE_ONLY = true;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-atLinksNavtree");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        AT_LINKS_NAVTREE = true;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-yamlV2");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        yamlV2 = true;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-devsite");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        devsite = true;
+                        // Don't copy any assets to devsite output
+                        includeAssets = false;
+                        USE_DEVSITE_LOCALE_OUTPUT_PATHS = true;
+                        mHDFData.add(new String[] {"devsite", "1"});
+                        if (staticOnly) {
+                            DEVSITE_STATIC_ONLY = true;
+                            System.out.println("  ... Generating static html only for devsite");
+                        }
+                        if (yamlNavFile == null) {
+                            // Use _toc.yaml as default to avoid clobbering possible manual _book.yaml files
+                            yamlNavFile = "_toc.yaml";
+                        }
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-android");
+                    @Override public int          getArgumentCount() { return 0; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return ""; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        auxSource = new AndroidAuxSource();
+                        linter = new AndroidLinter();
+                        android = true;
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-manifest");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<file>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        manifestFile = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        options.add(
+                new Option() {
+                    private final List<String> names = List.of("-compatconfig");
+                    @Override public int          getArgumentCount() { return 1; }
+                    @Override public String       getDescription() { return ""; }
+                    @Override public Option.Kind  getKind() { return Option.Kind.STANDARD; }
+                    @Override public List<String> getNames() { return names; }
+                    @Override public String       getParameters() { return "<config>"; }
+                    @Override public boolean      process(String opt, List<String> arguments) {
+                        compatConfig = arguments.get(0);
+                        return true;
+                    }
+                }
+        );
+
+        return options;
+    }
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    @Override
+    public boolean run(DocletEnvironment environment) {
+        return start(environment);
+    }
+
+    public static boolean checkLevel(int level) {
+        return (showLevel & level) == level;
+    }
 
   /**
    * Returns true if we should parse javadoc comments,
@@ -172,242 +1547,11 @@
   }
 
   public static void main(String[] args) {
-    System.exit(com.sun.tools.javadoc.Main.execute(args));
+    throw new UnsupportedOperationException("Not yet implemented");
   }
 
-  public static boolean start(RootDoc r) {
-    String keepListFile = null;
-    String proguardFile = null;
-    String proofreadFile = null;
-    String todoFile = null;
-    String sdkValuePath = null;
-    String stubsDir = null;
-    // Create the dependency graph for the stubs  directory
-    boolean offlineMode = false;
-    String apiFile = null;
-    String dexApiFile = null;
-    String removedApiFile = null;
-    String removedDexApiFile = null;
-    String exactApiFile = null;
-    String privateApiFile = null;
-    String privateDexApiFile = null;
-    String debugStubsFile = "";
-    String apiMappingFile = null;
-    HashSet<String> stubPackages = null;
-    HashSet<String> stubImportPackages = null;
-    boolean stubSourceOnly = false;
-    boolean keepStubComments = false;
-    ArrayList<String> knownTagsFiles = new ArrayList<String>();
-
-    root = r;
-
-    String[][] options = r.options();
-    for (String[] a : options) {
-      if (a[0].equals("-d")) {
-        outputPathBase = outputPathHtmlDirs = ClearPage.outputDir = a[1];
-      } else if (a[0].equals("-templatedir")) {
-        ClearPage.addTemplateDir(a[1]);
-      } else if (a[0].equals("-hdf")) {
-        mHDFData.add(new String[] {a[1], a[2]});
-      } else if (a[0].equals("-knowntags")) {
-        knownTagsFiles.add(a[1]);
-      } else if (a[0].equals("-apidocsdir")) {
-        javadocDir = a[1];
-      } else if (a[0].equals("-toroot")) {
-        ClearPage.toroot = a[1];
-      } else if (a[0].equals("-samplecode")) {
-        sampleCodes.add(new SampleCode(a[1], a[2], a[3]));
-      } else if (a[0].equals("-samplegroup")) {
-        sampleCodeGroups.add(new SampleCode(null, null, a[1]));
-      } else if (a[0].equals("-samplesdir")) {
-        getSampleProjects(new File(a[1]));
-      //the destination output path for main htmldir
-      } else if (a[0].equals("-htmldir")) {
-        inputPathHtmlDirs.add(a[1]);
-        ClearPage.htmlDirs = inputPathHtmlDirs;
-      //the destination output path for additional htmldir
-      } else if (a[0].equals("-htmldir2")) {
-        if (a[2].equals("default")) {
-          inputPathHtmlDir2.add(a[1]);
-        } else {
-          inputPathHtmlDir2.add(a[1]);
-          outputPathHtmlDir2 = a[2];
-        }
-      //the destination output path for additional resources (images)
-      } else if (a[0].equals("-resourcesdir")) {
-        inputPathResourcesDir = a[1];
-      } else if (a[0].equals("-resourcesoutdir")) {
-        outputPathResourcesDir = a[1];
-      } else if (a[0].equals("-title")) {
-        Doclava.title = a[1];
-      } else if (a[0].equals("-werror")) {
-        Errors.setWarningsAreErrors(true);
-      } else if (a[0].equals("-lerror")) {
-        Errors.setLintsAreErrors(true);
-      } else if (a[0].equals("-error") || a[0].equals("-warning") || a[0].equals("-lint")
-          || a[0].equals("-hide")) {
-        try {
-          int level = -1;
-          if (a[0].equals("-error")) {
-            level = Errors.ERROR;
-          } else if (a[0].equals("-warning")) {
-            level = Errors.WARNING;
-          } else if (a[0].equals("-lint")) {
-            level = Errors.LINT;
-          } else if (a[0].equals("-hide")) {
-            level = Errors.HIDDEN;
-          }
-          Errors.setErrorLevel(Integer.parseInt(a[1]), level);
-        } catch (NumberFormatException e) {
-          // already printed below
-          return false;
-        }
-      } else if (a[0].equals("-keeplist")) {
-        keepListFile = a[1];
-      } else if (a[0].equals("-showUnannotated")) {
-        showUnannotated = true;
-      } else if (a[0].equals("-showAnnotation")) {
-        showAnnotations.add(a[1]);
-      } else if (a[0].equals("-hideAnnotation")) {
-        hideAnnotations.add(a[1]);
-      } else if (a[0].equals("-showAnnotationOverridesVisibility")) {
-        showAnnotationOverridesVisibility = true;
-      } else if (a[0].equals("-hidePackage")) {
-        hiddenPackages.add(a[1]);
-      } else if (a[0].equals("-proguard")) {
-        proguardFile = a[1];
-      } else if (a[0].equals("-proofread")) {
-        proofreadFile = a[1];
-      } else if (a[0].equals("-todo")) {
-        todoFile = a[1];
-      } else if (a[0].equals("-public")) {
-        showLevel = SHOW_PUBLIC;
-      } else if (a[0].equals("-protected")) {
-        showLevel = SHOW_PROTECTED;
-      } else if (a[0].equals("-package")) {
-        showLevel = SHOW_PACKAGE;
-      } else if (a[0].equals("-private")) {
-        showLevel = SHOW_PRIVATE;
-      } else if (a[0].equals("-hidden")) {
-        showLevel = SHOW_HIDDEN;
-      } else if (a[0].equals("-stubs")) {
-        stubsDir = a[1];
-      } else if (a[0].equals("-stubpackages")) {
-        stubPackages = new HashSet<String>();
-        for (String pkg : a[1].split(":")) {
-          stubPackages.add(pkg);
-        }
-      } else if (a[0].equals("-stubimportpackages")) {
-        stubImportPackages = new HashSet<String>();
-        for (String pkg : a[1].split(":")) {
-          stubImportPackages.add(pkg);
-          hiddenPackages.add(pkg);
-        }
-      } else if (a[0].equals("-stubsourceonly")) {
-        stubSourceOnly = true;
-      } else if (a[0].equals("-keepstubcomments")) {
-        keepStubComments = true;
-      } else if (a[0].equals("-sdkvalues")) {
-        sdkValuePath = a[1];
-      } else if (a[0].equals("-api")) {
-        apiFile = a[1];
-      } else if (a[0].equals("-dexApi")) {
-        dexApiFile = a[1];
-      } else if (a[0].equals("-removedApi")) {
-        removedApiFile = a[1];
-      } else if (a[0].equals("-removedDexApi")) {
-        removedDexApiFile = a[1];
-      } else if (a[0].equals("-exactApi")) {
-        exactApiFile = a[1];
-      } else if (a[0].equals("-privateApi")) {
-        privateApiFile = a[1];
-      } else if (a[0].equals("-privateDexApi")) {
-        privateDexApiFile = a[1];
-      } else if (a[0].equals("-apiMapping")) {
-        apiMappingFile = a[1];
-      } else if (a[0].equals("-nodocs")) {
-        generateDocs = false;
-      } else if (a[0].equals("-noassets")) {
-        includeAssets = false;
-      } else if (a[0].equals("-nodefaultassets")) {
-        includeDefaultAssets = false;
-      } else if (a[0].equals("-parsecomments")) {
-        parseComments = true;
-      } else if (a[0].equals("-metalavaApiSince")) {
-        METALAVA_API_SINCE = true;
-      } else if (a[0].equals("-since")) {
-        sinceTagger.addVersion(a[1], a[2]);
-      } else if (a[0].equals("-artifact")) {
-        artifactTagger.addArtifact(a[1], a[2]);
-      } else if (a[0].equals("-offlinemode")) {
-        offlineMode = true;
-      } else if (a[0].equals("-metadataDebug")) {
-        META_DBG = true;
-      } else if (a[0].equals("-includePreview")) {
-        INCLUDE_PREVIEW = true;
-      } else if (a[0].equals("-ignoreJdLinks")) {
-        if (DEVSITE_STATIC_ONLY) {
-          DEVSITE_IGNORE_JDLINKS = true;
-        }
-      } else if (a[0].equals("-federate")) {
-        try {
-          String name = a[1];
-          URL federationURL = new URL(a[2]);
-          federationTagger.addSiteUrl(name, federationURL);
-        } catch (MalformedURLException e) {
-          System.err.println("Could not parse URL for federation: " + a[1]);
-          return false;
-        }
-      } else if (a[0].equals("-federationapi")) {
-        String name = a[1];
-        String file = a[2];
-        federationTagger.addSiteApi(name, file);
-      } else if (a[0].equals("-yaml")) {
-        yamlNavFile = a[1];
-      } else if (a[0].equals("-dac_libraryroot")) {
-        libraryRoot = ensureSlash(a[1]);
-        mHDFData.add(new String[] {"library.root", a[1]});
-      } else if (a[0].equals("-dac_dataname")) {
-        mHDFData.add(new String[] {"dac_dataname", a[1]});
-      } else if (a[0].equals("-documentannotations")) {
-        documentAnnotations = true;
-        documentAnnotationsPath = a[1];
-      } else if (a[0].equals("-referenceonly")) {
-        referenceOnly = true;
-        mHDFData.add(new String[] {"referenceonly", "1"});
-      } else if (a[0].equals("-staticonly")) {
-        staticOnly = true;
-        mHDFData.add(new String[] {"staticonly", "1"});
-      } else if (a[0].equals("-navtreeonly")) {
-        NAVTREE_ONLY = true;
-      } else if (a[0].equals("-atLinksNavtree")) {
-        AT_LINKS_NAVTREE = true;
-      } else if (a[0].equals("-yamlV2")) {
-        yamlV2 = true;
-      } else if (a[0].equals("-devsite")) {
-        devsite = true;
-        // Don't copy any assets to devsite output
-        includeAssets = false;
-        USE_DEVSITE_LOCALE_OUTPUT_PATHS = true;
-        mHDFData.add(new String[] {"devsite", "1"});
-        if (staticOnly) {
-          DEVSITE_STATIC_ONLY = true;
-          System.out.println("  ... Generating static html only for devsite");
-        }
-        if (yamlNavFile == null) {
-          // Use _toc.yaml as default to avoid clobbering possible manual _book.yaml files
-          yamlNavFile = "_toc.yaml";
-        }
-      } else if (a[0].equals("-android")) {
-        auxSource = new AndroidAuxSource();
-        linter = new AndroidLinter();
-        android = true;
-      } else if (a[0].equals("-manifest")) {
-        manifestFile = a[1];
-      } else if (a[0].equals("-compatconfig")) {
-        compatConfig = a[1];
-      }
-    }
+  public static boolean start(DocletEnvironment environment) {
+    root = new RootDocImpl(environment);
 
     // If the caller has not explicitly requested that unannotated classes and members should be
     // shown in the output then only show them if no annotations were provided.
@@ -423,7 +1567,7 @@
     }
 
     // Set up the data structures
-    Converter.makeInfo(r);
+    Converter.makeInfo(root);
 
     if (generateDocs) {
       ClearPage.addBundledTemplateDir("assets/customizations");
@@ -736,256 +1880,6 @@
     data.setValue("page.title", s);
   }
 
-
-  public static LanguageVersion languageVersion() {
-    return LanguageVersion.JAVA_1_5;
-  }
-
-
-  public static int optionLength(String option) {
-    if (option.equals("-d")) {
-      return 2;
-    }
-    if (option.equals("-templatedir")) {
-      return 2;
-    }
-    if (option.equals("-hdf")) {
-      return 3;
-    }
-    if (option.equals("-knowntags")) {
-      return 2;
-    }
-    if (option.equals("-apidocsdir")) {
-      return 2;
-    }
-    if (option.equals("-toroot")) {
-      return 2;
-    }
-    if (option.equals("-samplecode")) {
-      samplesRef = true;
-      return 4;
-    }
-    if (option.equals("-samplegroup")) {
-      return 2;
-    }
-    if (option.equals("-samplesdir")) {
-      samplesRef = true;
-      return 2;
-    }
-    if (option.equals("-devsite")) {
-      return 1;
-    }
-    if (option.equals("-yamlV2")) {
-      return 1;
-    }
-    if (option.equals("-dac_libraryroot")) {
-      return 2;
-    }
-    if (option.equals("-dac_dataname")) {
-      return 2;
-    }
-    if (option.equals("-ignoreJdLinks")) {
-      return 1;
-    }
-    if (option.equals("-htmldir")) {
-      return 2;
-    }
-    if (option.equals("-htmldir2")) {
-      return 3;
-    }
-    if (option.equals("-resourcesdir")) {
-      return 2;
-    }
-    if (option.equals("-resourcesoutdir")) {
-      return 2;
-    }
-    if (option.equals("-title")) {
-      return 2;
-    }
-    if (option.equals("-werror")) {
-      return 1;
-    }
-    if (option.equals("-lerror")) {
-      return 1;
-    }
-    if (option.equals("-hide")) {
-      return 2;
-    }
-    if (option.equals("-warning")) {
-      return 2;
-    }
-    if (option.equals("-error")) {
-      return 2;
-    }
-    if (option.equals("-keeplist")) {
-      return 2;
-    }
-    if (option.equals("-showUnannotated")) {
-      return 1;
-    }
-    if (option.equals("-showAnnotation")) {
-      return 2;
-    }
-    if (option.equals("-hideAnnotation")) {
-      return 2;
-    }
-    if (option.equals("-showAnnotationOverridesVisibility")) {
-      return 1;
-    }
-    if (option.equals("-hidePackage")) {
-      return 2;
-    }
-    if (option.equals("-proguard")) {
-      return 2;
-    }
-    if (option.equals("-proofread")) {
-      return 2;
-    }
-    if (option.equals("-todo")) {
-      return 2;
-    }
-    if (option.equals("-public")) {
-      return 1;
-    }
-    if (option.equals("-protected")) {
-      return 1;
-    }
-    if (option.equals("-package")) {
-      return 1;
-    }
-    if (option.equals("-private")) {
-      return 1;
-    }
-    if (option.equals("-hidden")) {
-      return 1;
-    }
-    if (option.equals("-stubs")) {
-      return 2;
-    }
-    if (option.equals("-stubpackages")) {
-      return 2;
-    }
-    if (option.equals("-stubimportpackages")) {
-      return 2;
-    }
-    if (option.equals("-stubsourceonly")) {
-      return 1;
-    }
-    if (option.equals("-keepstubcomments")) {
-      return 1;
-    }
-    if (option.equals("-sdkvalues")) {
-      return 2;
-    }
-    if (option.equals("-api")) {
-      return 2;
-    }
-    if (option.equals("-dexApi")) {
-      return 2;
-    }
-    if (option.equals("-removedApi")) {
-      return 2;
-    }
-    if (option.equals("-removedDexApi")) {
-      return 2;
-    }
-    if (option.equals("-exactApi")) {
-      return 2;
-    }
-    if (option.equals("-privateApi")) {
-      return 2;
-    }
-    if (option.equals("-privateDexApi")) {
-      return 2;
-    }
-    if (option.equals("-apiMapping")) {
-      return 2;
-    }
-    if (option.equals("-nodocs")) {
-      return 1;
-    }
-    if (option.equals("-nodefaultassets")) {
-      return 1;
-    }
-    if (option.equals("-parsecomments")) {
-      return 1;
-    }
-    if (option.equals("-metalavaApiSince")) {
-      return 1;
-    }
-    if (option.equals("-since")) {
-      return 3;
-    }
-    if (option.equals("-artifact")) {
-      return 3;
-    }
-    if (option.equals("-offlinemode")) {
-      return 1;
-    }
-    if (option.equals("-federate")) {
-      return 3;
-    }
-    if (option.equals("-federationapi")) {
-      return 3;
-    }
-    if (option.equals("-yaml")) {
-      return 2;
-    }
-    if (option.equals("-gmsref")) {
-      gmsRef = true;
-      return 1;
-    }
-    if (option.equals("-gcmref")) {
-      gcmRef = true;
-      return 1;
-    }
-    if (option.equals("-metadataDebug")) {
-      return 1;
-    }
-    if (option.equals("-includePreview")) {
-      return 1;
-    }
-    if (option.equals("-documentannotations")) {
-      return 2;
-    }
-    if (option.equals("-referenceonly")) {
-      return 1;
-    }
-    if (option.equals("-staticonly")) {
-      return 1;
-    }
-    if (option.equals("-navtreeonly")) {
-      return 1;
-    }
-    if (option.equals("-atLinksNavtree")) {
-      return 1;
-    }
-    if (option.equals("-android")) {
-      return 1;
-    }
-    if (option.equals("-manifest")) {
-      return 2;
-    }
-    if (option.equals("-compatconfig")) {
-      return 2;
-    }
-    return 0;
-  }
-  public static boolean validOptions(String[][] options, DocErrorReporter r) {
-    for (String[] a : options) {
-      if (a[0].equals("-error") || a[0].equals("-warning") || a[0].equals("-hide")) {
-        try {
-          Integer.parseInt(a[1]);
-        } catch (NumberFormatException e) {
-          r.printError("bad -" + a[0] + " value must be a number: " + a[1]);
-          return false;
-        }
-      }
-    }
-
-    return true;
-  }
-
   public static Data makeHDF() {
     Data data = jSilver.createData();
 
diff --git a/src/com/google/doclava/Errors.java b/src/com/google/doclava/Errors.java
index a7a3bdf..05ac006 100644
--- a/src/com/google/doclava/Errors.java
+++ b/src/com/google/doclava/Errors.java
@@ -315,6 +315,7 @@
   public static final Error NO_ARTIFACT_DATA = new Error(129, HIDDEN);
   public static final Error BROKEN_ARTIFACT_FILE = new Error(130, ERROR);
   public static final Error JAVA_TAG_IN_COMMENT = new Error(131, LINT);
+  public static final Error MULTIPLE_SDK_EXT_INFO = new Error(132, ERROR);
 
   public static boolean setErrorLevel(int code, int level) {
     for (Error e : sErrors) {
diff --git a/src/com/google/doclava/FieldInfo.java b/src/com/google/doclava/FieldInfo.java
index 40a3c81..99d208c 100644
--- a/src/com/google/doclava/FieldInfo.java
+++ b/src/com/google/doclava/FieldInfo.java
@@ -376,6 +376,7 @@
     TagInfo.makeHDF(data, base + ".deprecated", comment().deprecatedTags());
     TagInfo.makeHDF(data, base + ".seeAlso", comment().seeTags());
     data.setValue(base + ".since", getSince());
+    data.setValue(base + ".sdkextsince", getSdkExtSince());
     if (isDeprecated()) {
       data.setValue(base + ".deprecatedsince", getDeprecatedSince());
     }
diff --git a/src/com/google/doclava/MethodInfo.java b/src/com/google/doclava/MethodInfo.java
index ac6d2c5..3a8b1a8 100644
--- a/src/com/google/doclava/MethodInfo.java
+++ b/src/com/google/doclava/MethodInfo.java
@@ -19,7 +19,6 @@
 import com.google.clearsilver.jsilver.data.Data;
 import com.google.doclava.apicheck.AbstractMethodInfo;
 import com.google.doclava.apicheck.ApiInfo;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -630,6 +629,7 @@
     TagInfo.makeHDF(data, base + ".deprecated", deprecatedTags());
     TagInfo.makeHDF(data, base + ".seeAlso", seeTags());
     data.setValue(base + ".since", getSince());
+    data.setValue(base + ".sdkextsince", getSdkExtSince());
     if (isDeprecated()) {
       data.setValue(base + ".deprecatedsince", getDeprecatedSince());
     }
diff --git a/src/com/google/doclava/PackageInfo.java b/src/com/google/doclava/PackageInfo.java
index 25f229e..edef00d 100644
--- a/src/com/google/doclava/PackageInfo.java
+++ b/src/com/google/doclava/PackageInfo.java
@@ -208,6 +208,7 @@
     }
     data.setValue(base + ".name", name());
     data.setValue(base + ".since", getSince());
+    data.setValue(base + ".sdkextsince", getSdkExtSince());
   }
 
   public void makeClassLinkListHDF(Data data, String base) {
@@ -219,6 +220,7 @@
     ClassInfo.makeLinkListHDF(data, base + ".exceptions", exceptions());
     ClassInfo.makeLinkListHDF(data, base + ".errors", errors());
     data.setValue(base + ".since", getSince());
+    data.setValue(base + ".sdkextsince", getSdkExtSince());
   }
 
   public ClassInfo[] annotations() {
diff --git a/src/com/google/doclava/Stubs.java b/src/com/google/doclava/Stubs.java
index 930d52c..a90ed6e 100644
--- a/src/com/google/doclava/Stubs.java
+++ b/src/com/google/doclava/Stubs.java
@@ -53,7 +53,7 @@
       boolean keepStubComments) {
     // figure out which classes we need
     final HashSet<ClassInfo> notStrippable = new HashSet<ClassInfo>();
-    Collection<ClassInfo> all = Converter.allClasses();
+    Collection<ClassInfo> all = List.copyOf(Converter.allClasses());
     Map<PackageInfo, List<ClassInfo>> allClassesByPackage = null;
     PrintStream apiWriter = null;
     PrintStream dexApiWriter = null;
diff --git a/src/com/google/doclava/TypeInfo.java b/src/com/google/doclava/TypeInfo.java
index 4369036..b4dd9a5 100644
--- a/src/com/google/doclava/TypeInfo.java
+++ b/src/com/google/doclava/TypeInfo.java
@@ -17,8 +17,13 @@
 package com.google.doclava;
 
 import com.google.clearsilver.jsilver.data.Data;
-
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 public class TypeInfo implements Resolvable {
   public static final Set<String> PRIMITIVE_TYPES = Collections.unmodifiableSet(
@@ -31,6 +36,9 @@
     mDimension = dimension;
     mSimpleTypeName = simpleTypeName;
     mQualifiedTypeName = qualifiedTypeName;
+    if (mQualifiedTypeName == null) {
+      int x = 5;
+    }
     mClass = cl;
   }
 
@@ -121,6 +129,9 @@
       mQualifiedTypeName = typeString;
     } else {
       mQualifiedTypeName = typeString;
+      if (mQualifiedTypeName == null) {
+        int x = 5;
+      }
       pos = typeString.lastIndexOf('.');
       if (pos > -1) {
         mSimpleTypeName = typeString.substring(pos + 1);
@@ -140,6 +151,9 @@
     mDimension = other.dimension();
     mSimpleTypeName = other.simpleTypeName();
     mQualifiedTypeName = other.qualifiedTypeName();
+    if (mQualifiedTypeName == null) {
+      int x = 5;
+    }
     mClass = other.asClassInfo();
     if (other.typeArguments() != null) {
       mTypeArguments = new ArrayList<TypeInfo>(other.typeArguments());
@@ -162,6 +176,10 @@
       mResolvedClass = true;
       if (mClass == null && !mIsPrimitive && !mIsTypeVariable && !mIsWildcard) {
         mClass = Converter.obtainClass(qualifiedTypeName());
+        if (mClass == null) {
+          int x = 5;
+          mClass = Converter.obtainClass(qualifiedTypeName());
+        }
       }
     }
     return mClass;
@@ -317,6 +335,7 @@
       if (mClass.isIncluded()) {
         data.setValue(base + ".link", mClass.htmlPage());
         data.setValue(base + ".since", mClass.getSince());
+        data.setValue(base + ".sdkextsince", mClass.getSdkExtSince());
       } else {
         Doclava.federationTagger.tag(mClass);
         if (!mClass.getFederatedReferences().isEmpty()) {
@@ -501,7 +520,10 @@
                   mResolutions.add(resolution);
                   allResolved = false;
               } else {
-                  mClass = InfoBuilder.Caches.obtainClass(qualifiedClassName.toString());
+                mClass = InfoBuilder.Caches.obtainClass(qualifiedClassName.toString());
+                if (mClass == null) {
+                  int x = 5;
+                }
               }
           } else if ("variability".equals(resolution.getVariable())) {
               StringBuilder qualifiedClassName = new StringBuilder();